按 2026-09-19 的用户要求,后续 Linux 构建、PX4/Gazebo 仿真和服务联调默认使用现有云服务器。本机负责代码编辑和快速单测;scripts/dev_stack.py 只操作 cloud,连接失败不会启动本地 Docker。
初始 M0 部署见 2026-09-19 历史验收。当前应用 SHA、部署 ID 和状态以 status 及本次部署回执为准;历史测试数字不能转借到新版本。
M1 已通过 2026-09-20 完整验收,原里程碑运行版本为 eefe76e。D027 实时入口补遗的部署版本和新增验证以 实时入口验收 为准;本机页面、云端运行与后续文档归档提交分开记录。
M0 未解锁冒烟继续作为部署前置;M1 另有 sim/aircraft/ground 三镜像、executive/guardian 双进程和独立裁判。M2 在同一工作区增加 sim2 仿真镜像(多一个蓝色资产)、ground 镜像中的 mission-service、aircraft 镜像中的 uplink,以及项目 secrets/ 下的签名密钥与 mTLS 证书;端到端用例按需启停,不常驻。M3(D038)再增加 m3-aircraft(ROS 2 Jazzy、外部模式出口节点、事件检测)与 m3-sim(x500_vision、深度相机、M3 世界)两个镜像,用例按需启停;M3 SITL 上限 2.0 CPU / 2 GiB(D045),自主层 0.6、出口节点 0.25、事件检测 0.5 CPU。真机的 guardian、控制出口与飞控连接仍在设备侧,云端只验证模拟飞控。
工作区使用 SSH 用户的 ~/drone-agent/,不放入 car-agent 目录。Docker project 为 drone-agent-cloud;SITL 限 1.5 CPU / 2 GiB,契约测试限 1 CPU / 1 GiB。仿真网络为内部桥接,测试容器无网络,二者不发布宿主端口。SSH 用于部署与管理。
D027 增加固定 M1 任务的 实时浏览器入口:dev_stack.py console 在本机回环地址提供页面,经 SSH 读取云端并提交有界操作。云端不增加公开服务端口;它与后续 M2 的 mission-service/审批控制台分开验收。
D028 将网页常驻到云端,使用仅绑定宿主 127.0.0.1:8768 的受限容器和专用任务代理,由独立 Tailscale Serve HTTPS 8447 入口提供私网访问。日常体验不再需要本机桥;dev_stack.py console-cloud --status 返回地址,配置与准确版本见 Tailnet 指南 和 验收记录。它不启用 Funnel、不改变既有其他映射,也不新增应用登录体系。
配置依据:Compose 资源属性、内部网络。验收还会读取实际容器设置,确认配置已经生效。
D037 将常驻使用入口统一到 8448:主页为 M2,/fixed/ 为 M1。升级顺序是 deploy --apply → console-cloud --apply → desk-cloud --apply,最后用 desk-cloud --status 核对同版本健康;使用与新增挂载见 飞行台指南,评审证据见 2026-09-24 记录。
连接参数来自进程环境,不写入仓库、部署清单或 .env:
| 参数 | 含义 |
|---|---|
DRONE_AGENT_DEPLOY_HOST |
云主机地址或 SSH 主机名 |
DRONE_AGENT_DEPLOY_USER |
用户名,默认 ubuntu |
DRONE_AGENT_SSH_IDENTITY |
已有 SSH 私钥路径,只供本机 SSH 使用 |
没有设置 DRONE_AGENT_DEPLOY_HOST 时,复用已配置的 CAR_AGENT_DEPLOY_HOST / CAR_AGENT_DEPLOY_USER / CAR_AGENT_SSH_IDENTITY。一旦指定 DRONE 主机,就必须完整提供它的身份,不能混用另一主机的密钥。脚本不读取 car-agent .env,不上传私钥。SSH 使用 BatchMode 与严格 known-host 校验;原始 SSH banner 不进入日志。
在仓库根目录执行:
$env:UV_DEFAULT_INDEX = 'https://pypi.tuna.tsinghua.edu.cn/simple'
uv run python scripts/dev_stack.py target
uv run python scripts/dev_stack.py status
uv run python scripts/dev_stack.py verify
uv run python scripts/dev_stack.py test
uv run python scripts/dev_stack.py logs
uv run python scripts/dev_stack.py stop
uv run python scripts/dev_stack.py startverify 在云端容器内接收遥测并检查 Gazebo 时钟,不发控制命令。test 在云端对当前部署的应用 commit 执行完整 pytest;默认 importlib 模式保持不变,失败、错误或跳过都会使本轮验证不通过。测试容器退出后保留,便于审计,不自动删除。
status 只读检查目标、容量、镜像与当前项目容器;它不创建工作区、不部署、不启动容器。stop/start 仅作用于本项目 SITL。
先部署已提交版本,再显式运行:
uv run python scripts/dev_stack.py m1 --scenario nominal --seeds 7
uv run python scripts/dev_stack.py m1 --scenario all --seeds 7,19,41这两个命令会在云端仿真中解锁/起飞。场景清单为 configs/scenarios/m1_suite.yaml;指定部署的不可变源码定义实际任务、种子随机化、注入与裁判。默认 m1 跑正常任务的三个种子。任一失败即停止本批扩展并保留产物,不能只按进程退出零判断通过,必须检查回执 status 与各项 passed。
共享主机的验收默认 --speed-factor 1;显式 --speed-factor 2 用于单独的加速实验,报告中的 measured_sim_speed 才是实际倍率。--scenario faults 选择故障子集,也可用逗号列出若干场景;这些子集回执不能单独关闭 M1。完整准出由 scripts/verify_m1_release.py 按指定 SHA 中的场景与种子清单核对。
镜像从已校验的检查镜像构建并按 SHA 命名;bc 仅安装在仿真镜像内,供 PX4 标准加速时钟启动脚本使用。MAVSDK 固定 3.17.4,其电量单位为 0–100,在适配器边界转换为契约的 0–1。航线上传后等待 PX4 异步检查,再确认实际进入 MISSION;依据为 PX4 官方 MAVSDK 集成测试。
同一时刻仅运行一个场景。SITL 1.5 CPU/2 GiB,guardian 0.6 CPU/512 MiB,executive 0.4 CPU/512 MiB,采集器 0.3 CPU/256 MiB,离线裁判 0.5 CPU/512 MiB;无主机端口。只有 guardian 与模拟飞控共享网络;executive 无网络,只有私有 UDS。真值目录不挂载给机载进程。
产物位于 artifacts/<deployment_id>/m1-<run_id>/<scenario>-<seed>/:input/ 固定任务与注入、aircraft/ JSONL/MCAP/实际影像/能力快照/进程身份、truth/ Gazebo 真值、ulog/ 飞控原始日志、judge/ 裁判结果。progress.json 可查看长批次进度,build-*.log 实时写入构建输出。实验结束恢复本项目空闲 SITL;历史记录和旧镜像不自动删除。
离线重判使用同一版本 ground 镜像执行 python3 -m drone_agent.eval.judge <run目录> --root /workspace --output <结果文件>。裁判复算影像、真值轨迹、前驱门控与 MCAP 事件一致性。新规则重判必须保留旧结果并标注新的软件 SHA。
部署已提交版本后运行(会在云端仿真中解锁 / 起飞):
uv run python scripts/dev_stack.py m2 --scenario nl_inspect_red --seeds 7
uv run python scripts/dev_stack.py m2 --scenario all --seeds 7,19,41场景集为 configs/scenarios/m2_suite.yaml:红 / 蓝资产的自然语言请求(种子选择三种措辞)、第一版影像被抹平后的策略批准重试、飞行全程任务服务停机、应拒答请求、被骗规划器扩大范围。每个用例依次:生成输入 → 启动 SITL 与真值采集 → 启动 mission-service 与 uplink → 以 harness:m2-<run>-<case> 身份经服务 API 提交请求 → 按确切 package_hash 审批 → 等 uplink 验签并写入 inbox → 每个任务版本用新 guardian / executive 与新代次飞行 → 等服务镜像追平两本账本 → 导出服务视图 → 在线与 MCAP 回放各跑一次 eval/judge_m2.py。回执 suite.json 记录签名密钥 ID、证书指纹与其他容器身份。
--planner scripted(默认)使用 m2_prepare 生成的带标注脚本回答,只证明服务、签名、上行、飞行与报告链路,不能当作模型行为或准入率基线。--planner live 需要先把本机进程环境里的 MINIMAX_API_KEY 写入云端项目 secrets:
uv run python scripts/dev_stack.py m2-key # 只返回计划
uv run python scripts/dev_stack.py m2-key --apply # 写入 secrets/m2-model/minimax.key(0600),不回显本机的 key 只放在进程环境里,本项目不读 .env(D029)。需要推送或更换云端 key、重跑准入率基线,或者让本机任务台实调时,在自己的 PowerShell 窗口临时设为用户环境变量;输入不回显,也不进命令历史:
$k = Read-Host "MINIMAX_API_KEY" -AsSecureString
[Environment]::SetEnvironmentVariable("MINIMAX_API_KEY", [Net.NetworkCredential]::new("", $k).Password, "User")
# 用完删除,云端副本不受影响:
[Environment]::SetEnvironmentVariable("MINIMAX_API_KEY", $null, "User")已经打开的终端和 Claude Code 会话不会自动继承新设的用户变量,需要在命令里读取 [Environment]::GetEnvironmentVariable("MINIMAX_API_KEY", "User"),或者重开会话。本机环境若设有 SOCKS 的 ALL_PROXY,httpx 会因缺少 socksio 在发请求前失败。MiniMax 是国内端点,只在该命令的进程里移除 ALL_PROXY,并把 api.minimaxi.com 加入 NO_PROXY 直连即可。
密钥与证书由 fleet/provision.py 在 ground 镜像中以工作区用户身份生成到 ~/drone-agent/secrets/m2/,重复运行保留签名密钥;它们不进入快照、Compose 文件、镜像或日志。
产物位于 artifacts/<deployment_id>/m2-<run_id>/<scenario>-<seed>/:input/(场景、脚本回答、故障文件)、service/(业务账本、媒体、ready.json、实调录制)、inbox/、mailbox/、uplink/、robot/、aircraft/<mission_id>/v<n>/(每个版本一次飞行)、truth/、ulog/、service-export/、judge/。拉取与人工核对沿用 fetch;证据浏览器对 M2 用例按任务版本各生成一条记录,并显示规划事件带与规划 / 审批 / 报告 / 复核 / 问题表。
准入率基线只在本机、有密钥时运行,会产生模型费用:
uv run python scripts/m2_baseline.py --output docs/verification/m2-baseline-<日期>.json --price-input <元/百万> --price-output <元/百万> --price-source "<厂商价格页与日期>"没有给出价格来源时费用记为 unpriced。基线以 HEAD 记录软件版本,门禁要求所有判据来自同一 commit;要给已验证过的候选补基线,在该候选的独立工作树里运行(步骤见 M2 验收记录)。门禁输入哈希按字节计算、仓库按 LF 存储,门禁拒收 CRLF 输入。
常驻任务台(D035):dev_stack.py desk-cloud 只读计划,--apply 构建当前部署版本的 M2 镜像、在 secrets/desk/ 生成任务台自己的信任根、启动 desk / desk-service / desk-uplink 并安装仿真监管者 unit,新增 Serve 8448 映射;--status 返回入口与监管者状态。批准的任务由监管者持项目锁飞行,所以任务台飞行与部署、M1 / M2 批次及 D028 运行互斥,排队时页面显示「等待云端工作区」。使用与边界见 任务台指南。
本机任务台 uv run python -m drone_agent.console.mission --local 在 http://127.0.0.1:8769 提供 hri.v0 控制台和进程内任务服务:提交、规划、准入、审批与签名都在本机完成,没有机器人连接,不起飞(D023);有 MINIMAX_API_KEY 时实调规划,否则只回答 M2 场景集中的请求原文,页面标明所用规划器。M2 是否关闭只看 scripts/verify_m2_release.py:在同一 commit 上核对云端检查、对抗语料、E2E、M1 完整回归与实调基线,缺证据的判据记为 missing。
部署已提交版本后运行(会在云端仿真中解锁 / 起飞,并启动外部模式出口节点与自主层):
uv run python scripts/dev_stack.py m3 --scenario ext_inspect --seeds 7
uv run python scripts/dev_stack.py m3 --scenario ext_inspect,ext_goto --seeds 7,19,41 --keep-going
uv run python scripts/dev_stack.py m3 --scenario ext_inspect,route_fallback --seeds 7,19,41 --edge off --keep-going
uv run python scripts/dev_stack.py m3 --scenario ext_inspect --seeds 7,19,41 --edge-period 0 --isolation shared场景集为 configs/scenarios/m3_suite.yaml(16 个场景,覆盖观测过期、任务卡住、网络中断、计算过载四类与定位、能源、事件检测的辅助场景),逐场景期望见 m3_expectations.yaml。首次运行按版本构建四个镜像:drone-agent-m1-ground、drone-agent-m2-sim、drone-agent-m3-aircraft(ROS 2 Jazzy、px4_msgs / px4_ros2_cpp 固定版本、出口节点、事件检测的 ONNX Runtime 与 CLIP 视觉编码器)与 drone-agent-m3-sim(x500_vision、前视深度相机、M3 世界);ROS 2 基础层、事件检测运行时与提示嵌入层只依赖固定输入,跨版本复用。每个用例依次:等主机安静窗口(CPU 压力与负载降下来,最多 10 分钟,等待情况写入回执)→ 启动 SITL 与真值采集 → 相机转接与 XRCE agent → 出口节点、自主层与事件检测 → guardian(外部模式任务先等出口节点与 PX4 连通、自主层给出有结论的定位报告,最多 90 s,结果写入账本 external_ready,D048)→ executive;飞行中按场景在声明的边界注入故障;结束后在线与 MCAP 回放各跑一次 eval/judge_m3.py,外部模式用例再生成单独归档的影子报告 judge/shadow.json。
--keep-going:失败后继续跑完所选用例(诊断与测量批次);默认首个失败即停。--edge off/--edge-period 0/--isolation shared:D040 的测量档位(关闭事件检测;连续推理;guardian 与自主层、事件检测绑定到同一核心)。档位写入每个用例的measure.json与回执。- 回执
suite.json/progress.json的每个用例另记:资源采样汇总(各容器 CPU、节流、内存与主机 CPU 压力,原始数据在resources.jsonl)、仿真停顿列表、事件检测延迟与真值一致率、外部模式计数、安静窗口等待与 Mesa 着色器缓存条目数。 - 仿真停顿:共享主机上 llvmpipe 首次编译着色器或 CPU 争用会让 Gazebo 整体冻结;项目工作区
cache/mesa-shaders-m3/持久化着色器缓存,冷缓存运行可能出现一次性停顿。由停顿引发的新鲜度恢复被裁判判为void_simulator_stall,必须同版本同种子重跑,不计通过也不计系统失败(D045)。
产物位于 artifacts/<deployment_id>/m3-<run_id>/<scenario>-<seed>/:input/(任务包、场景、注入文件)、aircraft/(guardian / executive 账本与 MCAP、影像、状态与监督统计)、egress/(出口节点证据)、autonomy/(规划、感知证据)、edge/(事件检测逐帧记录)、truth/、ulog/、judge/(裁判结果、回放结果、影子报告、飞控事件)、resources.jsonl、measure.json、quiet-gate.json。M3-SITL 是否通过只看 scripts/verify_m3_release.py:同一 commit 上的云端检查、对抗语料、M3 场景集、M1 与 M2 回归、M2 的 Zenoh 子集、D040 测量与 v2 恢复边绑定;M3-JIL 缺硬件时记为 missing,M3 本身不能关闭。门禁与绑定都在只增加记录与文档的后代提交上运行,只接受隔离成立、整批通过的回执;其余回执另存,不作为输入:
uv run python scripts/bind_recovery_edges.py --sha <被测版本> --m3 <M3 场景集回执> --m1 <M1 回执> --apply
uv run python scripts/verify_m3_release.py --sha <被测版本> --deployment <部署回执> --m3 <场景集与测量回执> --m1 <M1 回执> --m2 <gRPC 回执> --m2-zenoh <Zenoh 回执> --output <门禁结果>2026-09-25 的候选证据按这一布局归档在 docs/verification/m3-2026-09-25/(计入的回执按类别分目录,not-counted/ 与先前候选的 diagnostics/ 分开保存),见 M3 验收记录。
M2 的 Zenoh 传输(D046):dev_stack.py m2 --scenario nl_inspect_red,service_outage --seeds 7,19,41 --transport zenoh 在同一 M2 编排与裁判下让服务与 uplink 走 Zenoh(TLS + mTLS + 按证书名的访问控制);默认 --transport grpc 不变。
裁判结论是机器产出;人工核对用证据浏览器。它读取的正是裁判读取的产物,只展示与复算摘要,不产生也不修改判定。
uv run python scripts/dev_stack.py runs
uv run python scripts/dev_stack.py fetch --run m1-<run_id> --cases nominal-7,cancel_cruise-7
uv run python scripts/dev_stack.py fetch --run m1-<run_id> --cases nominal-7,cancel_cruise-7 --apply --artifacts D:/drone-agent-cloud
uv run python -m drone_agent.eval.viewer D:/drone-agent-cloud/runs/<deployment_id>/m1-<run_id>runs 只读列出云端 artifacts/ 下的运行及其回执摘要,不占用变更锁。fetch 默认只返回计划(用例、文件数、字节数);--apply 经 SFTP 拉取到本地 ASCII 目录 runs/<deployment_id>/<run>/,逐文件核对远端清单摘要,对裁判散列过的文件再与回执比对;任何差异都报错、写入 fetch.json 并且不生成页面。--receipt 指定归档回执(如 docs/verification/m1-2026-09-20-receipt.json)时,另报告云端回执是否与归档一致。--exclude ulog,sensor 跳过大文件;--cases all 拉整批。远端只有 runs / inspect 两个只读动作,拉取不改变服务器状态。
拉取成功后自动生成 viewer.html(单文件、离线、只读)。页面内容:裁判结论与期望、错误成功数、离线重判一致性;ENU 俯视轨迹(Gazebo 真值与 guardian 观测估计叠加,批准体积、登记航线、资产、降落点);高度曲线、时间轴与事件带(任务 / 控制权 / 安全 / 操作者 / 注入);任务步骤三元判定与状态迁移;影像证据(原始 RGB 无损转 PNG,媒体哈希、采集位姿、真值距资产距离);监督周期 p99 与终态;账本哈希链、MCAP 事件重放、文件 SHA-256 与裁判 / 回执摘要核对;飞控 ULog 模式迁移摘录;原始文件清单。ULog 本身用 PX4 Flight Review 或 PlotJuggler 打开。
页面不是证据:证据是拉取目录里的原始文件与它们的摘要。页面显示不一致或缺席时以原始文件和裁判结果为准。设计原则与后续扩展点见 评测体系 §7。
应用源码固定为指定的已提交 commit,且必须从本地 main 可达。工具不会自动 commit 或 push,脏工作树中的应用改动不进入源码包。远端执行脚本、Compose、验证 Dockerfile 与锁定依赖另以 control_sha256 绑定;验收时必须同时报告应用 SHA 与控制面哈希。
# 先查看计划,再执行同一来源的部署。
uv run python scripts/dev_stack.py deploy --sha HEAD
uv run python scripts/dev_stack.py deploy --sha HEAD --apply首次引导增加 --bootstrap-images,复用已经验证的 M0 镜像,并用 --artifacts D:/drone-agent-cloud 指定 ASCII 传输目录。此步骤只导出现有镜像,不在本机重新构建或运行真栈。归档经 SSH 传输后,远端核对 SHA-256、允许的镜像标签、文件系统层和运行配置;出现不同的同名镜像时拒绝覆盖。
较慢或中断的上传可用 deploy --resume <原 artifact_directory> --apply 继续。SFTP 只续传不可变的大归档,小文件重新完整传输;续传前检查本地包哈希,传完后仍验证远端整体 SHA-256。控制脚本已变化时拒绝复用旧部署包。
部署在服务器上构建契约验证镜像,依赖从指定 commit 的 uv.lock 导出并带哈希安装到独立虚拟环境,与镜像内的 ROS Python 包隔离。随后启动受限 SITL,运行未解锁冒烟与完整契约测试,比较其他容器的 ID、镜像、启动时间与重启次数。全部通过后才更新 current.json。更新失败时恢复本项目上一部署;首次部署失败则停止本项目 SITL。现有 car-agent 的容器、数据、环境与入口不属于操作范围。
~/drone-agent/
├─ owner.json / stack.lock / current.json
├─ incoming/<run_id>/ # 校验过的源码、控制文件和引导归档;部署当次解包到 releases/ 后不再读取
├─ releases/<run_id>/
│ ├─ source/ # git archive 的应用 commit
│ ├─ control/ # Compose、验证 Dockerfile、锁定依赖
│ └─ manifest.json
├─ secrets/ # 0700;m2/ 签名密钥、trust、CA 与 mTLS 证书,m2-model/ 实调 key(均 0600)
├─ cache/mesa-shaders-m3/ # M3 SITL 共享的 Mesa 着色器缓存(D045);只影响渲染耗时,可随时删除重建
└─ artifacts/<run_id>/ # 构建日志、冒烟 JSON、JUnit、部署回执;m1-*/、m2-*/、m3-*/ 为飞行批次;ULog 见下文压缩说明
同一项目的变更使用独立 flock 串行化,不占用 car-agent 发布锁。重任务开始前检查共享服务器余量;当前部署要求至少 3 GiB 可用内存、8 GiB 可用磁盘。归档、旧部署、停止的测试容器和证据不自动清理;不改系统设置、安全组、Tailscale、systemd、CI/CD 或数据库 schema。
ULog 压缩存放(2026-09-27):artifacts/ 下当时已有的 1030 个 PX4 ULog 已持项目锁用 zstd -3 无损压缩为 *.ulg.zst,共 17.2 GB → 4.9 GB。
- 每个部署目录的
ulog-compression.json记录各文件的相对路径、原始字节数与 SHA-256。回执和裁判摘要里的.ulg摘要都指原文件,用zstd -dc <文件>.ulg.zst | sha256sum即可对上;压缩时已逐个回算,并抽查过 P3 最终候选回执中的 10 个摘要。 fetch照常可用:压缩文件按远端清单核对,回执里的.ulg条目因原名不存在而不参与第二见证比对。用 Flight Review 或 PlotJuggler 打开前先解压。- 此后新运行产生的 ULog 仍是原始格式,累积后可按同样的方式再压缩:持锁,逐文件回算摘要后再删原件。
- 常驻空闲仿真已关闭 ULog 记录(D062),不再在容器内累积日志。
- 2026-09-28 按同样方式又压缩了 59 个:1.09 GB → 0.30 GB;原件摘要与已提交的 P4 回执逐个对上。
- 2026-10-09 又压缩了 284 个,共 4.71 GB → 1.30 GB:
artifacts/下 165 个,来自 P5 的 S1、回归与 M2 批次。1716843部署目录的 65 个摘要与已提交的 P5 回执逐个对上。- 常驻任务台
desk/flights/下 119 个,首次压缩。清单在desk/flights/ulog-compression.json,路径相对该目录。任务台飞行的 ULog 只在飞完后的在线 / 回放裁判时读取,长稳裁判只读各飞行的flight.json。
- 2026-10-11 又压缩了 85 个,共 1.86 GB → 0.52 GB:
artifacts/下 82 个(P4 S2 复验、P6 补拍与 P6 对抗录制期间的 S1 与回归批次),任务台desk/flights/下 3 个;逐个回算解压后的摘要与原件一致才删原件。同次清理删除了 3 个不计入的中间版本镜像(c660ff9、21810bc、f68b90f)和 20 个已解包的传输包,可用空间 48.6 → 50.6 GB,其他项目的容器前后一致。 - 2026-10-13 又压缩了 20 个(D084 的 P3 S1 比较批次),0.60 GB → 0.16 GB;原件摘要与已提交的 D084 S1 回执 20/20 一致。
镜像与账本备份的保留(2026-10-13 起,用户批准):
- 镜像:只留三类。
- 当前部署版本:控制台与任务台在用。
- 任务台的上一版:用于回滚。
- M0 基础镜像:部署时会核对它们的指纹。
- 里程碑与实调环境:以 git 提交和已归档回执为准,不再长期保留镜像。理由:
- 构建不拿旧镜像当缓存来源:
--pull=false,没有--cache-from; - 门禁只读回执;
- 删掉的版本可按
releases/<部署>/或 git 重建。
- 构建不拿旧镜像当缓存来源:
- 删镜像的做法:先删本项目钉住旧版本的已退出一次性容器(compose 每次都会重建),再删镜像,
docker rmi不加-f。 - 账本迁移前的完整备份:迁移通过门禁后,较早的那份一旦被下一次迁移前的备份取代就可以删,最新一份保留。
- 2026-10-13 按此清理(持项目锁):
- 删除 38 个版本的 176 个标签和 27 个已退出容器;
- 删除 13 个已解包的传输包;
- 删除 D085 迁移前的账本备份(1.2 GB,已被 D087 迁移前的备份取代,后者
quick_check为 ok); - 按记录 ID 删除本项目 41 条构建缓存(4.42 GB,名单外 0 条,做法见下文)。
- 结果:可用空间 46.99 → 70.88 GiB;控制台与任务台仍为 ready。同一时段 car-agent 正好发布,它的容器因此重建,与本次清理无关。
sshd 握手限流(2026-10-12,用户批准的系统配置例外):
- 现象:公网扫描长期占满 sshd 的 10 个未认证名额。
LoginGraceTime 420是为微信扫码登录(pam_qrlogin.so)保留的,所以扫描连接最长挂 7 分钟。部署、回执与查询的 SSH 握手因此被随机丢弃,表现为exit 255/no valid JSON;24 小时内限流 33 次。 - 改动:新增
/etc/ssh/sshd_config.d/60-drone-agent-startups.conf:PerSourceMaxStartups 5、MaxStartups 40:30:120;LoginGraceTime不变。 - 应用方式:先
sshd -t校验并热加载,再由一条新连接确认;120 s 内没有确认就自动撤销。 - 撤销:删除该文件后执行
systemctl reload ssh。
构建缓存与共享主机(2026-09-28):
- BuildKit 构建缓存由本项目与 car-agent 共用。按构建步骤与父层归属后,不被镜像引用的缓存里本项目占大头。当天已按记录 ID 删掉本项目已被取代版本的 292 条、18.64 GB。做法:
- 同时设
--max-used-space与--reserved-space作保底; - 先用匹配不到任何记录的条件试运行,再单删一条,最后批量删。
- 同时设
- 双方约定的主机级回收:car-agent 按其授权安装并维护
host-capacity-gc,每小时一轮。- 可用空间低于 45 GiB 时才回收构建缓存。
- 回收后仍低于 60 GiB 就记下退避状态,可用空间再降 5 GiB 才重试。
- 任一项目的锁被占用就跳过这一轮,prune 期间不持锁。
- 回收时的保底:2026-10-09 起保留 10 GiB。2026-10-13 本项目用户同意撤销保底,由 car-agent 在其用户批准后实施:回收时一次清空全部可回收的缓存。原因是删掉任何一条记录后,BuildKit 都会解绑留下记录的缓存键,保底留下的副本再也命中不了,本项目每次回收后的下一次构建照样重建 venv。
- 另外两项约定:journald 上限 1G;
/var/lib/apport/coredump中的 core 由 apport 自带的 tmpfiles 规则在 3 天后删除,比 GC 的 7 天规则更早。
- 暂缓的根因修复:
sim/m1.Dockerfile的 sim 阶段与sim/p3.Dockerfile在每次提交都会变的镜像之上执行apt-get update后安装bc,每次都留下约 275 MB 的软件包索引。- 修法是把
bc的安装挪到检查镜像,并在同一步删掉/var/lib/apt/lists。 sim/m1.Dockerfile属于门禁的机载冻结清单,改动需完整 M1 回归,因此等下次机载改动本来就要跑 M1 回归时一并修。
- 修法是把
- 主机约束:
- 不调用
docker buildx history:2026-09-27 它触发过 dockerd panic,同机全部容器随之停止。 - dockerd 没有开启 live-restore,任何 daemon 重启都会停掉两边的全部容器;涉及 daemon 配置的改动须放在双方约定的维护窗口里。
- 不调用
应用测试结果只属于回执中的 source_sha;本地新增云端工具测试不计入该应用 commit 的云端测试数字。M0 历史证据保持原样,云端验证单独记录。
验证镜像使用 pip 支持的 独立 Python 环境管理,不为测试而改变 ROS 的依赖版本。
P0 的 verify_p0_release.py 用法与证据见 P0 记录。P1 的资源、虚拟机场与领取闸门(D055)及账本 schema v2(D056)已实现;P2 的持久工作流(D057)与工作流扩展表(D058)已实现;P3 的多站多机调度(D059)、调度扩展表(D060)与两机同世界 SITL(D061)已实现;P4 的业务闭环(D063)、业务扩展表(D064)与 S2 评测协议(D065)已实现;P5 的平台目录、第二业务模板、厂商网关、长稳与门禁(D069–D073)已实现,命令如下。P1–P5 的 S1 选择是「用例 × 种子」的交集(--scenario a,b --seeds 7,41 会对两个用例各取其种子列表中的 7 与 41);门禁每个用例 × 种子只收一次,分批时不要让同一用例的种子跨批重复。M1 / M2 没有作废规则:共享主机上仿真冻结(真值记录中约 0.5 s 墙钟内仿真几乎不前进)引起观测过期、版本数不符时,先用真值与 guardian 记录核实,把原回执与诊断存证据目录的 not-counted/,再同版本整批重跑,不改任何阈值。
| 用途 | 命令 | 说明 |
|---|---|---|
| S0 故障矩阵 | uv run python -m drone_agent.eval.p1_world --output <目录> |
本机即可运行;14 场景 × 3 种子;正式任务服务 + 逻辑机场 + 运行真实机载进程的逻辑飞行器;独立裁判在线与回放各判一次;主机停顿(如休眠)使该次尝试作废并重跑,保留记录 |
| S1 用例 | uv run python scripts/dev_stack.py p1 --scenario all [--keep-going] |
云端 compose.m2.yaml + compose.p1.yaml;uav_01 在 PX4 SITL 上经虚拟机场的领取闸门飞行、审批后维护阻断、飞行中服务与机场后端重启,共 5 例 |
| 拉取 S1 产物 | uv run python scripts/dev_stack.py fetch --run p1-<运行ID> --cases p1_s1_nominal-7 --apply |
摘要核对同 M2 |
| 常驻任务台成员 | uv run python scripts/dev_stack.py desk-members --apply |
经 tailnet 读取本机在任务台的身份,写入云端 secrets/desk/members.yaml(0600);登录名不进仓库、不进回执 |
| 常驻任务台 | desk-cloud --apply |
激活前在当前账本副本上运行 D056 迁移演练(只留计数与摘要),通过后才切换;服务启动时带备份迁移 |
| 发布门禁 | uv run python scripts/verify_p1_release.py ... |
见 P1 记录 |
| P2 S0 矩阵 | uv run python -m drone_agent.eval.p2_world --output <目录> |
本机即可运行;P2-F01–F15 × 3 种子:P1 世界加工作流引擎,只经正式 API 驱动;独立裁判 eval/judge_p2.py 在线与回放各判一次,并带 P1 派遣 / 释放 / 飞行检查 |
| P2 S1 用例 | uv run python scripts/dev_stack.py p2 --scenario all [--keep-going] |
云端 compose.m2.yaml + compose.p1.yaml + compose.p2.yaml;服务加载 p2_s1_v1 工作流目录;编排按人的方式逐任务审批、复核、维修反馈;链路 × 3 种子(两次飞行含复检)、飞行中取消、飞行中重启服务,共 5 例;裁判逐任务跑 M2 飞行裁判再做 P1 / P2 检查 |
| 草案对抗语料 | uv run python -m drone_agent.eval.workflow_adversarial |
工作流草案注入语料(脚本替身);生效 / 越权草案必须为 0 |
| 常驻任务台(P2) | desk-members --apply 后 desk-cloud --apply |
成员列表给本机身份加 reviewer;激活前在同一账本副本上先后运行 D056 与 D058 演练,服务启动时带备份加上工作流表 |
| P2 发布门禁 | uv run python scripts/verify_p2_release.py ... |
见 P2 方案 与验收记录 |
| P3 S0 矩阵 | uv run python -m drone_agent.eval.p3_world --output <目录> |
本机即可运行;P3-F01–F15 × 3 种子:两组相邻站点 + 隔离项目的逻辑世界加调度器,只经正式 API 驱动;独立裁判 eval/judge_p3.py 在线与回放各判一次,并带 P1 派遣 / 释放 / 飞行检查 |
| P3 规模阶梯 | uv run python -m drone_agent.eval.p3_world --part ladder --output <目录> |
10 / 30 / 100 个逻辑节点(每节点一台逻辑 UAV + 一个逻辑机场,从不算飞行器);闭环任务流,按档报告判定耗时、分配延迟、等待与拒绝分布 |
| P3 S1 用例 | uv run python scripts/dev_stack.py p3 --scenario all [--seeds 7] [--keep-going] |
云端 compose.p3.yaml:一个 Gazebo 世界、PX4 实例 0 / 1(uav_01 / uav_02)各自的机载栈、证书与逻辑机场;执行器先停本项目空闲 SITL、选空闲私网段、等安静窗口,批次首例先做 60 s 空闲容量探针;经常驻 API 中继调用服务,两架飞行互不等待;每例记录各容器 CPU / 内存 / 节流与主机负载,按飞行窗口算实时因子并读 guardian 监督周期 p99(D061 限值不满足即不通过);共 5 例 |
| 常驻任务台(P3) | desk-cloud --apply |
服务另带 p3_desk_v1 调度目录;激活前在同一账本副本上依次运行 D056、D058 与 D060 演练,服务启动时带备份加上调度表 |
| P3 发布门禁 | uv run python scripts/verify_p3_release.py ... |
见 P3 方案 与验收记录 |
| P4 S0 矩阵 | uv run python -m drone_agent.eval.p4_world --output <目录> |
本机即可运行;P4-F01–F15 × 3 种子:P2 世界加外观世界、业务引擎与脚本视觉替身,只经正式 API 驱动;独立裁判 eval/judge_p4.py 在线与回放各判一次,并带 P1 / P2 检查 |
| P4 S1 用例 | uv run python scripts/dev_stack.py p4 --scenario all [--keep-going] |
云端 compose.m2.yaml + compose.p1.yaml + compose.p4.yaml;编排经 Gazebo 世界的 create / remove 服务放置与移除损伤贴片(换电重启世界后按需恢复),按人的方式审批、复核发现与本轮、报告维修;关单 × 3 种子、未修复一轮、去重,共 5 例;裁判逐任务跑 M2 飞行裁判,再做 P1 / P2 / P4 检查与世界真值核对 |
| S2 数据安装 | uv run python scripts/dev_stack.py p4-data --data <本机数据目录> [--apply] [--resume <上传ID>] |
本机按已提交清单核对后,只把清单中的文件打成确定性归档,经可续传 SFTP 上传;云端拒绝链接与目录穿越,逐文件核对后只读安装到 ~/drone-agent/data/visa_pcb_v1,从不覆盖已安装的数据 |
| S2 评测 | uv run python scripts/dev_stack.py p4-s2 --split calibration|test --mode live|replay|scripted|retrieval [--threshold τ] [--replay-of <部署>/p4-<运行>] |
live 只经白名单代理到达模型端点并逐样本录制;replay 与 scripted 无网络;校准运行给出阈值表,测试运行给出冻结指标,回放与所回放的实调运行逐样本比较;retrieval 在 M3 同版本 CLIP 的无网络评测镜像中给出检索报告(不设门槛) |
| 常驻任务台(P4) | desk-cloud --apply |
服务改带 p4_s1_v1 工作流目录并另带 p4_s1_v1 业务目录与实调视觉角色;激活前在同一账本副本上依次运行 D056、D058、D060 与 D064 演练,服务启动时带备份加上业务表 |
| P5 S1 用例 | uv run python scripts/dev_stack.py p5 --scenario all [--seeds 7] [--keep-going] |
云端 compose.m2.yaml + compose.p1.yaml + compose.p4.yaml + compose.p5.yaml;P5 仿真镜像(M2 世界加道路标线),机载 uplink / guardian / executive 加载 P5 S1 地图;编排经 Gazebo 世界服务放置与移除道路障碍物,以 event:road-reports 发出道路报告并按人的方式审批与复核;结果另带每次分析的道路特征占比,供区间标定记录 |
| 常驻任务台(P5) | desk-members --next --apply 后 desk-cloud --apply |
成员列表先暂存(列出 fleet_s0 / vendor_s3 会使旧服务拒绝启动),激活时才替换、失败即恢复;构建 P5 仿真镜像、为逻辑飞行器签发证书,在同一账本副本上依次运行迁移演练与 P5 目录切换演练;服务带四个 p5_desk_v1 目录、三种执行后端与厂商链路,另起 desk-fleet 与 desk-vendor,等四个机场会话都活动后才完成 |
| 任务台世界 | uv run python scripts/dev_stack.py desk-world --section s1|s0|s3 --asset <资产> --state normal|damaged|obstructed --apply |
只写主机上的世界文件并记历史;监管者起飞前放置 S1 模型,逻辑机队与厂商模拟器按各自一节渲染;任务服务与页面读不到 |
| 长稳 | uv run python scripts/dev_stack.py desk-soak --start|--status|--stop|--judge [--apply] |
以 systemd unit 运行 scripts/desk_soak.py,计划为 configs/soak/p5_soak_v1.yaml;--judge 复制账本后在无网络容器中运行长稳裁判;见运维手册 |
| 备份与恢复演练 | desk-backup --apply、desk-restore-drill --apply |
在线备份账本并记录媒体清单;演练把最近的备份恢复到临时目录离线读回,从不触碰在用账本 |
P1/P2 联调复用现有云端单机 mission_upload 与项目锁,不需要 Jetson。P3 的两机同世界拓扑与容量预算见 D061;S0 的 10/30/100 逻辑节点规模与 S1 物理实例数分别记录。保持 guardian 独立配额、项目隔离与按需 SITL,不自动改动其他项目或系统配置。
H1 承接 M3-JIL。原 verify_m3_release.py 的总门禁仍会因 JIL 缺席而 not_passed;P 系列未来门禁单列所需软件能力与硬件缺项,不覆盖历史结果。运营存储 schema / 迁移的具体方案先完成审查并按项目红线获批,再实施(D056、D058 均已获批)。