chore(task): archive 10-04-slim-distribution

This commit is contained in:
Antigravity committed 2026-10-05 00:20:57 +00:00
1 parent 4fda7c8c1a
commit a2e0436ed4
8 files changed
+6 -5

No files matched your search

@@ -0,0 +1,5 @@
{"file":".trellis/spec/backend/quality-guidelines.md","reason":"Focused checks and actual CLI verification"}
{"file":".trellis/spec/backend/toolchain-and-library.md","reason":"Distribution security and offline invariants"}
{"file":".trellis/tasks/10-04-slim-distribution/prd.md","reason":"Required deliverables and acceptance criteria"}
{"file":".trellis/tasks/10-04-slim-distribution/design.md","reason":"Implementation boundaries and exact restore contract"}
{"file":".trellis/tasks/10-04-slim-distribution/implement.md","reason":"Verification evidence and ownership"}
@@ -0,0 +1,37 @@
# 精简发行设计
## 修改边界与复用
现有 `packaging` 统一签名全部资源,`release_source` 下载单一 gzip,`MachineManager` 原子安装版本,daemon 保护共享缓存,`InstalledRegistry` 从安装版本取工具。改动必须落在这些 owner:不向 App/业务配置加入安装概念,不重复实现每种生态的下载器/进程监督器,不把 Rust 源码编译要求转给使用者。
保留源码签名、路径/类型/摘要校验、四种数据库 profile、系统服务权限范围、离线编译、失败前置和版本 journal 的既有语义。CLI/安装/缓存/SDK/skill 的改变属于已确认五项方案;语言语法、模型、业务运行时与其他宿主平台不变。
## 发行目录与认证
- 升级当前发行 schema:签名根 manifest 包含基础 `artifacts` 和封闭类型的扩展目录 `extensions`。每个扩展绑定 kind、target 和完整 artifact 列表,身份由根 manifest 精确字节摘要与扩展 ID 共同确定。单一根签名认证全部描述,不能信任单独下载的无绑定元数据。
- 基础包包含 host native runtime 四 profile、core/lib、bootstrap、host sandbox、skill;Runtime(pip/npm/go)、Build(pip/npm)、Target(linux-aarch64 native+target sandbox) 分开发布。纯 Python/npm 包不触发 Build。
- author maker 继续只复制/校验/签名显式输入。预备发行目录可同时包含待发布扩展,SDK publisher 输出 base `.tar.zst` 与每种扩展 `.tar.zst`,文件列表来自同一签名目录。既有 v0.1.0 tag 不覆盖,正式新产物使用新版本。
- Zstandard 固定长窗口上限 27、流式解压、压缩/解压/文件数/单文件/尾部边界仍受限;不以签名成功替代归档检查。Rust 使用维护中的 codec 库安全接口,不手写 codec 或新增 workspace unsafe。
- Python 首装沿用独立发行公钥+OpenSSL 认证根目录,再下载并逐字节校验 raw bootstrap launcher 及其已声明私有动态库到独立 scratch。使用已认证 launcher 的隐藏 extraction 入口解压 `.tar.zst`,然后运行现有 bootstrap;使用者无需系统 zstd。完整解压/路径规则复用 Rust owner,避免保留两套 TAR 安全实现。SDK 发布上述 raw blob 供引导,所有可执行字节必须在执行前经独立密钥和摘要验证。
## 扩展安装、读取与更新
- 资源存储位于现有 service 可写的 `cache/extensions` 下,按已安装签名 manifest 身份与扩展 ID 建立不可变目录;不扩大 systemd 写范围,不写用户家目录,不修改版本 core 树或签名数据。
- 新 IPC 只接收 `version + ExtensionId(kind,target)` 封闭枚举,不接受 URL、路径、脚本或解压参数。官方 HTTPS origin、redirect allowlist、字节/时限/并发限额由工具链固定。外部用户复用现有 peer authentication/admission,只能准备已安装可信版本目录里声明的扩展。
- 复用持久 install 锁,下载在私有 staging,验证完整列表和字节后原子 no-replace 发布;竞态仅在完整同身份校验通过后复用。缺失是准备提示,损坏必须拒绝,不能悄悄掩盖成 cache miss。
- 单一只读资源视图统一 base 与已安装扩展路径,所有 worker runtime/build/sandbox 和目标 runtime 读取共用它;编译和缓存命中不得触发下载。源 manifest 不被拼接改写成伪造签名数据。
- `target add linux-aarch64` 对当前 active 版本显式准备 target 扩展;Lib preparation 额外准备实际使用生态对应 target。目标是应用 ARM,不要求 ARM 宿主编译器。
- `update` 准备新 base,并把当前 active 版本已经安装的扩展选择全部准备到新版本身份下,再写同一个 active journal。任何前置失败保留旧 active/core/skill/扩展,已安装资源不重复下载;未使用扩展不被顺带安装。
## Lib 恢复
- 显式 add/update/install 及 Package 中真正准备 Lib 的动作进入同一 preparation scope。先取得未绑定 Worker 声明,按需准备 Runtime,然后通过现有 owner 绑定和解析;普通 check/doctor/remove/run/build 保持只读或既有离线语义。
- Build 仅在 resolver 已确认 sdist 或 npm hook 必需后由统一 build-input owner 准备,不能根据生态名称一律下载。
- `lib install` 消费当前格式准确锁:验证项目、Package 传递依赖与 checked Worker binding;缓存命中验证完整 bytes/hash;缺失时按锁定精确版本/源定位下载,不选择新版本。完成后 setting/lock 字节保持一致。
- 为原生构建收据补全准确源 locator/文件名、固定 build requirement closure、原始 npm 执行图和编译输入身份;当前格式一并迁移仓库 fixtures,不引入旧格式 fallback。重放只能使用锁定输入;最终产物必须符合原收据 bytes/hash,不能用不同产物改写原锁。不可重现明确失败。
## 质量与操作边界
主任务串行协调 Cargo,worker 不并发创建新 target。测试只选择发行/资源/Lib/安装路径,真实验收使用 owned 镜像和进程,不修改宿主服务、安全策略或真实数据库。正式优化构建与四种 runtime 档案来源分开记录。压缩收益不与重复内容字节直接相减;实际发布前报告 base download/install、raw bootstrap 开销及扩展增量。
公开 Release 和线上更新独立于本地签名包验收。若缺 GitHub API 登录,先完成可审查的源码与产物,再报告唯一外部阻塞,不能以 tag/源码 push 代替 Release。
@@ -0,0 +1,8 @@
{"file":".trellis/spec/backend/index.md","reason":"Rust compiler scope and check routing"}
{"file":".trellis/spec/backend/directory-structure.md","reason":"Module ownership and root test placement"}
{"file":".trellis/spec/backend/quality-guidelines.md","reason":"Focused validation and safe Rust"}
{"file":".trellis/spec/backend/error-handling.md","reason":"Explicit errors and resource cleanup"}
{"file":".trellis/spec/backend/toolchain-and-library.md","reason":"Signed toolchain, offline resources and Lib contracts"}
{"file":".trellis/tasks/10-04-slim-distribution/design.md","reason":"Approved scope and cross-owner contracts"}
{"file":".trellis/tasks/10-04-slim-distribution/research/release.md","reason":"Release call chain and security invariants"}
{"file":".trellis/tasks/10-04-slim-distribution/research/libs.md","reason":"Lock restore and preparation call chain"}
@@ -0,0 +1,57 @@
# 实施记录
## 已确认
- 用户已批准完整五项方案及任务创建/继续实施,无需重复确认相同范围。
- [x] 工作区起点核查和备份,`target/distribution-before.10dsis`,gzip 校验通过。
- [x] PRD 记录用户要求、范围、回滚和验收,非语言迁移任务。
- [x] research/release.md 和 research/libs.md 完成,按实际 owner 完成 API 对接。
- [x] 实施上下文配置、任务进入 in_progress。
## 实施顺序与责任
1. 发行/扩展 worker:根 catalog schema、Zstandard Rust owner、资源视图、共享扩展安装 IPC、target 命令、installed-extension update、Rust 隐藏 extraction 入口;拥有 toolchain 下相关模块、launcher binary、CLI Cargo dependency 和对应定向测试。不要修改 author packaging、SDK Python、skills 或 Lib resolver owner。
2. Lib worker:锁/收据当前格式与精确恢复、add/update/install/Package preparation scope、InstalledRegistry 资源读取接线、CLI lib help 与相关测试;拥有 libs/**、必要 workers 资源消费/Package 路径及 main.rs。与发行 worker对接 typed extension API,不重复实现下载/安装。
3. 主会话:author packaging 接 catalog、SDK asset publisher、Python 首装、skill/docs、最终构建及真实发行验收。三个 owner 先固定接口,避免同文件改动;若遇所有权交叉先沟通。
4. trellis-check 独立检查整个改动范围并修复;主会话核验关键结果,更新 canonical spec 和记录,然后按已有授权处理 Git 与可用的发行发布。
## 验证清单
- [x] codec/manifest:10 定向通过;bootstrap执行位另有断言。
- [x] install/cache/update:4 定向通过(并发/损坏/更新失败/已装集合/closedIPC/typedmiss);实际 UID65533/65534 共享扩展通过。
- [x] lib install:4 cold restore、2 npm cache/projection、1 Package exact closure、PEP517 nested replay、npm optional replay 定向通过;实际安装版三生态无 Lib Worker 的锁恢复/运行/构建通过。
- [x] 运行/构建缺资源只提示,不联网;target add 支持 ARM,实际 ARM64 ELF 交叉构建通过。
- [x] SDK/Python bootstrap 10/10、skill quick_validate、全部修改/新增 Rust 文件 rustfmt check、CLI lib/bins/author examples clippy -D warnings/type check 通过。
- [x] 正式 release 构建、core/launcher/daemon ELF closure、保留 runtime 档案链接符号。
- [x] 实际签名包基础首装:普通/Markdown new/fmt/check/test/run/build;不含可选生态和 ARM 文件。
- [x] 实际扩展准备/锁恢复/跨项目复用、ARM 构建、已准备资源离线和独立应用执行。
- [x] 安装/更新失败恢复和成功更新:定向回归通过;真实负载本地后继 catalog 的 4 阶段更新事务验收通过。公开网络单独阻塞,不混同。
- [x] 清理本次 owned 临时产物,保留 durable assets、hash、验收 JSON 和源码备份。
- [x] 最终 diff/self review、任务进度、Git 提交/push 和 Release 状态准确记录。实现与本地验收完成;公开 Release 条件未满足,仍属既有公开发行待办。
## 构建资源
起始磁盘约 0.78 GiB 空闲,/dev/shm 约 1.4 GiB 空闲。必要时可回收上一轮由本会话创建的隔离安装镜像(正式包与验收记录已持久保存且先复核),不可删除其他项目、源码、keys、未知 cache 或实验。使用显式 Rust toolchain 路径,保留现有共享 target,Cargo 串行 -j1;不因磁盘不足跳过必要验收或宣称完成。
## 当前证据
- 首轮 SDK/Python installer 定向 10/10,通过基础/扩展资产分离、真实 Ed25519 验签、raw bootstrap 摘要/长度/私有库、发布竞态、流量边界。Rust 接管的归档拒绝测试由发行 worker 补齐,未以 Python mock 代替实际安装验收。
- Cargo 新增静态 zstd 0.13.3;工作区版本 0.1.1,release strip=symbols,runtime-pack 仍显式 strip=debuginfo。正式串行构建目录 `/dev/shm/dever-slim-cargo.PvjPZZ`,未运行全量 CI。
- 旧 v0.1.0 完整 archive SHA-256 重新核对为 `7b56e825fb2b0468a271276bffbd84775e9dd9ae219f7e16097d1ff3df22b1cc` 后回收 owned 1.5 GiB 临时镜像。正式旧包/验收记录/源码备份均保留。
- Cargo 自有 `clean -p dever-cli -p dever-core --profile dev --target-dir target` 回收 898.3 MiB 旧编译产物;仅 native-acceptance-init 验收助手另存 `target/release-0.1.1/tools/`。源码/依赖缓存/其它项目/全局服务未清理。
- 真实本地 sandbox PEP517 nested replay 142.15s、npm optional replay 61.70s,均通过。原生maker 25/25默认定向通过,10个独立重验收未在这条命令启动。旧cross sandbox fixture已补齐同组native input;不是删除失败检查。
- trellis-check 独立审查未发现其他Rust合同问题;主会话修复其SDK bounded metadata/path长度/namespace/hostTarget差异,补文件/目录重叠拒绝。主会话另修复解压bootstrap执行位。clippy唯一is_multiple_of诊断已修复并复验通过。
- 原正式build先完成了全部依赖和CLI类型检查;在最终ELF链接前因上述代码修正主动停止(exit130)。最终源码 release 构建已成功(6m39s),产物保存到 `target/release-0.1.1/tools/`。core 16,951,872 字节,launcher 3,330,288 字节,daemon 3,310,296 字节;ELF 已 strip,launcher/daemon 仅需私有 libgcc_s 和 OS ABI,core 的 LLVM/private closure 随包提供。
## 真实 0.1.1 产物与验收
- 已制作实际签名 v2 目录与全部 split assets。基础 `.tar.zst` 为 117,481,208 字节(112.04 MiB),SHA-256 `fbf04562012b40038c8d845dcf528070606b4fd8374edec34c6516ea4afdf167`;基础文件解压合计约 573 MiB。首装另有 raw helper 3,513,312 字节(3.35 MiB)和约 22 KiB 元数据。全部可选资产合计约 596.59 MiB,不代表默认下载这些资源。
- `target/release-0.1.1/sizes.json` 记录每个资产的字节数/摘要;`provenance.json` 记录显式输入及未修改 runtime 档案复用。host glibc 最低 2.39,ARM64 为应用交叉目标。
- 首次实包验收到普通/Markdown 项目和缺 ARM 资源提示均通过;跨 UID 步骤因 outer bwrap 单 UID 映射不能 setgid65534 而失败。修复的是验收夹具:使用既有测试模式,在私有 machine 启动独立 daemon,以真实 UID65533/65534 检查共享资源。产品代码/签名资产未改;重新从 durable assets 验收。
- 更新验收另用真实负载签署仅供本地测试的后继版本,传输指向本地真实扩展。Ed25519 PKCS#8 v2 由与 maker 相同的 ring 签署,不再使用不支持该作者密钥格式的 OpenSSL 私钥读取;正式安装的 OpenSSL 公钥验证未变。最终 `update-acceptance.json` 为 passed,4 阶段通过:安装/扩展基线、失败保留旧活动版本且项目可运行、成功激活核心/skill/恰好已装扩展、切回真实版本后项目继续运行。仅供验收的 0.1.2 catalog 不能冒充 0.1.2 编译器,托管编译器严格拒绝目录版本与编译版本不同;没有关闭这项产品校验,也不声称虚拟后继版本执行通过。
- 实包从 durable assets 复验最终 `acceptance.json` 为 passed,13 阶段全部通过:签名首装、可选资源排除、公共入口/版本、普通与 Markdown 各自完整新项目流程、skill、离线缺资源、ARM64、三生态、双 UID、五个程序脱离源码/机器目录且清空 Worker 缓存后执行。全程未启动全局服务、未替换全局命令;本地传输不表示线上更新通过。
- 独立 trellis-check 对新增验收夹具/作者助手再次限定复核,无阻塞。产品验证合计 Rust 48 项、Python 10 项;正式实包 13 阶段、更新事务 4 阶段通过。fmt/clippy/skill 检查通过;未运行无关全量 CI/压力测试。
- 仅为回收本轮已完成的测试产物,Cargo clean CLI dev profile 再释放 376.8 MiB;正式包、作者输入、源码备份保留。
- 所有本轮隔离安装镜像均已卸载,自有 daemon/namespace 已退出;空临时目录已移除。正式构建临时目录核对仅含本轮 Rust 缓存/产物,保留工具与正式资产后清理约 556 MiB tmpfs。该目录没有新版 Cargo clean 要求的 CACHEDIR.TAG,未补造标记,核对归属后按精确目录移除;可从源码重建。
- 核心提交 `4fda7c8c1a33b843e2fca219cb3bc95c09471716`、skill 提交 `27ac8f21c2e82458e00161154e277eb742c6a231` 已分别推送到两个官方仓库 main;`v0.1.1` 标签已推送并指向核心工作提交。发布包不包含后续仅记录/归档提交的变化。GitHub API 未登录,Release 资产尚未上传,线上首次下载/更新未运行;不能将已推送标签等同于发布完成。
- GitHub SSH 源码访问可用;GitHub Release API 尚未登录。不能把源码/tag push 或本地模拟传输当作公开发布及线上更新。
@@ -0,0 +1,33 @@
# Dever 精简发行与按需工具安装
## 目标与已确认范围
用户已确认五项实施方案,并于本轮确认创建任务和继续实施。默认 Linux x86_64 基础包目标约 120 MiB,功能保持完整:编译器、LLVM、四种本机运行库(base/sqlite/postgres/both)、CLI、sandbox、skill 与模板。Python/Node/Go、原生扩展构建工具和 ARM 应用交叉编译资源改为显式命令触发、自动判断的按需安装。整台机器多用户、多项目共享同版本资源。
## 事实与约束
- 当前完整发行压缩包 714.7 MiB;同一基础文件集 gzip 为 181.6 MiB,Zstandard 长窗口(128 MiB)为 118.0 MiB,解压约 624 MiB。这是压缩试算,实际正式构建与完整安装验证仍需执行。
- 源码备份:`target/distribution-before.10dsis/source.tar.gz`;独立 skill 备份 `skills.tar.gz`;发行记录备份 `release-records.tar.gz`,均已 gzip 完整性校验。工作起点主仓库 `83b78a0`、skill `9fd78fc`,工作区干净。
- 编译器、launcher、daemon 应改为正式优化构建,清理非必要符号;保持 runtime 链接需要的符号。
- 应用配置仅 `config/setting.json`;官方源属于工具链内置元数据,不能放进项目配置或新增环境变量配置。不得依赖系统 PATH 的 Python/Node/Go/Rust 来构建用户应用。
- `run/build` 保持离线,缺资源提供准确准备命令;Dever Package 保持源码发布,底层 Rust 运行库保持预编译,FFI、自举和其他宿主平台不在本任务内。
- 当前 v0.1.0 源码 tag 已推送但二进制 Release 未发布;不得覆盖已有 tag。用户已授权相关仓库 commit/push。公开发布需完整验收和可用 GitHub API 授权,不能把本地包或 tag 当作已发布。
- 不改宿主 AppArmor/sysctl/全局服务,不替换机器全局命令;验收使用隔离安装镜像和自有进程。磁盘有限,复用现有工具输入并避免重复 Cargo target。
## 需求
1. 正式基础发行包采用 Zstandard,安装器和更新器具备所需解压能力,用户无需手动安装 zstd。完整性校验、边界限制、拒绝路径逃逸与原子发布继续成立。
2. 扩展按 Dever 版本、目标平台和内容身份绑定;按需签名下载、原子安装、并发安全、缓存复用,扩展失败不破坏已有可用版本。
3. `dever lib add/update` 自动准备声明所需生态环境,只有确有必要才准备原生构建工具;`dever lib install <project-root>` 按现有锁文件恢复,不更新版本、不改 setting/lock。
4. `dever target add linux-aarch64` 为当前选定版本准备 ARM 交叉编译资源;使用第三方 Lib 的 ARM 项目仍显式准备目标依赖。既有 ARM 能力与离线构建保持。
5. `dever update` 同步核心、skill 和已安装扩展;新增版本准备失败时旧 active 版本可继续使用,不能隐式安装所有可选扩展。
6. 同步 SDK 发行工具、安装脚本、CLI 帮助、开发 skill 和文档,命令行为只有一套实现,不新增兼容别名或重复路径。
## 验收
- 实际正式构建,报告压缩包大小与安装占用;约 120 MiB 为基于已有内容的目标,超出时必须报告准确实测和原因。
- 基础安装不包含 Python/Node/Go、原生扩展构建工具或 ARM 专用资源;普通与 Markdown 项目 new/check/test/run/build 通过隔离的定向验收。
- 需要什么下载什么;已有资源复用;锁文件恢复前后字节不变;无锁、锁与声明不符、资源损坏与下载失败均明确失败。
- 全新机器式隔离环境验证首次安装、扩展安装、多项目共享、已装扩展随更新和失败恢复;资源准备后断网构建,最终程序脱离工具链可执行。
- 定向恶意/损坏元数据和压缩边界回归通过;ARM 至少验证交叉构建及既有适用的隔离证据,不能把构建成功当作物理 ARM 性能测试。
- 公开上传和线上更新单独记录为完成或具体阻塞,不混同本地验收;不运行无关全量测试/长测。
@@ -0,0 +1,159 @@
# Research: Lib 按需准备与精确锁恢复
- Query: 追踪 Lib、Worker、Package 的准备/离线消费路径,设计 `dever lib install <root>` 与扩展管理器接点。
- Scope: internal;仅源码阅读,无测试、构建、下载、Git 操作。
- Date: 2026-10-04
## Findings
### 归属与已读规范
实际研究仓库为 `/data/project/dever`,独立 Rust 语言编译器,不是 `/data/project/shemic` 的 Go 应用。已读仓库 `AGENTS.md`、`.trellis/workflow.md`、当前 `prd.md`、backend index 与 toolchain-and-library 中目标、生态、锁、缓存和 Worker 合同,以及仓库 `skills/SKILL.md`。全局 shemic-dever/framework reference 描述 Go 项目,不能覆盖本仓库事实。
`task.py current --source` 返回 none;输出目录由主代理明确指定,未建立/修改会话指针。
### Files found
| 文件 | 作用 |
| --- | --- |
| `crates/dever-cli/src/libs.rs` | 锁结构、显式命令、已安装 runtime 读取、校验与离线嵌入 |
| `crates/dever-cli/src/libs/mutation.rs` | 稳定 inode 的项目依赖互斥锁 |
| `crates/dever-cli/src/libs/registry.rs` | 官方源安全传输、PyPI/npm/Go 解析及产物缓存发布 |
| `crates/dever-cli/src/libs/registry/npm.rs` | 独立 npm 环境、精确实例图、归档展开与需构建判断 |
| `crates/dever-cli/src/libs/registry/sumdb.rs` | Go 已锁透明日志证据与 ZIP 校验 |
| `crates/dever-cli/src/libs/build.rs` | 构建 Inputs、Session、完整 Receipt、离线收据校验 |
| `crates/dever-cli/src/libs/build/python.rs` | sdist 解包、PEP517 build 依赖解析与隔离执行 |
| `crates/dever-cli/src/libs/build/npm.rs` | npm 生命周期执行、optional 剪枝、最终安装归档 |
| `crates/dever-cli/src/libs/build/npm/environment.rs` | Node/Python/native 工具与 sandbox 环境 |
| `crates/dever-cli/src/workers/runtime.rs` | maker/consumer 共享 runtime descriptor 校验 |
| `crates/dever-cli/src/workers/go_build.rs` | 已准备 host Go 工具编译 target Worker |
| `crates/dever-cli/src/packages.rs` | Package 解析、精确 ZIP、源码/Worker/Lib 汇入公共锁 |
| `crates/dever-cli/src/toolchain/service.rs` | daemon ArtifactGet/Put IPC |
| `crates/dever-cli/src/toolchain/launcher.rs`、`src/main.rs` | 选版本与公共参数路由 |
### 现有调用链与准备入口
1. `libs::execute_for_target` (`libs.rs:1870`) 在 add/update 中先读声明、`source_workers`、Package libs,再 `resolve_project`,最后写 setting/lock。不能将 install 实现为 add/update 别名。
2. `source_workers_with_packages` (`libs.rs:2173`) 加载源码、check,再 `bound_program_workers` (`1236`)。后者立即调用 `InstalledRegistry::runtime` 绑定每个非 exec Worker 的 runtime。因此只在 `resolve_project` (`612`) 加 ensure 太晚:全新精简安装会先失败。无 Lib 的 managed Worker 也需要 runtime。
3. `resolve_project` 为实际生态调用 `InstalledRegistry::runtime` (`648`),创建 `HttpRegistry::official`、sumdb、`build::Session`,交给 resolver。fixture 全 exec 分支完全离线,不应强制要求 managed 安装。
4. `packages::execute_locked` (`1109`) 的 add/update 解析 Package closure,然后 `source_workers_with_packages` (`1173 附近`) 和 `resolve_project` (`1193 附近`)。Package 的传递 Lib 与 Worker 必须享有同一显式准备能力;remove 则 `retain_locked_libs`,不得顺便安装扩展。
5. `prepare` (`libs.rs:1139`) 名称易误导:它只校验声明是否在锁中并统计大小,不下载、不校验缓存完整性。
6. `embedded_resources_for_target` (`1268`) 在离线路径核对 runtime identity、目标、每个归档摘要/长度和 Go sumdb,再把字节作为资源。`prepare_resources` (`1418`) 追加目标 sandbox,Go 另外需要 host sandbox,随后 `workers::prepare_for_target`。
7. `workers/go_build.rs:61` 的 `compile_worker` 是离线构建;Go 编译器/链接器/selector/target stdlib 目前在 Go **runtime pack** 中,非 `build/go` 原生扩展包。保持 host 工具 + target 输出区分。
### 扩展管理器最小 API 接点
主代理提出使用 daemon 可写的不可变 `cache/extensions`,catalog 绑定已签名核心。Lib 层可保留当前逻辑路径,无需另一份生态业务实现:
- `ensure_extension(version, kind, target)`:仅显式准备阶段调用;kind 至少 runtime(pip/npm/go)、build(pip/npm)、target。目标 extension 包含 native runtime/target sandbox;生态 target runtime 单独选取。
- `read_verified_extension_artifact(version, kind, target, relative)` 与有界 artifact listing:只读验证已安装 extension,返回缺资源的准确准备命令。`InstalledRegistry::runtime` (`791`)、`build::Inputs::tools` (`726`)、`sandbox_resources` (`839`) 共用这个验证 owner,避免保留各自手写签名读取。当前 `signed_artifact` (`817`) 仅从 core manifest.artifacts 查叶子,需切换到合并后的已验证资源读取。
- 显式 preparation wrapper 实现 `build::Inputs`,runtime/tools 可先 ensure 再读。普通 InstalledRegistry 永远只读;或者使用显式、不可隐式默认的 preparation policy,并沿 worker 绑定路径传递。
- `source_workers_with_packages` 保持只读供 doctor/remove/run/build;新增同一底层源码扫描的显式准备入口,先收集未绑定 Worker,再 ensure、绑定。Package add/update 必须走该入口。不要复制 SourceMap/check 逻辑。
- npm build environment 自身请求辅助 Python (`build/npm/environment.rs:57`);按需准备需覆盖此调用,不能只看顶层 npm 声明。
- cross target 的本机 runtime、sandbox 与目标资源由类型化 target 选择,不能全局修改 host identity。
### 何时真的需要 build extension
- Python:优先兼容 wheel;只有进入 `RegistryResolver::python_source_candidate` (`registry.rs:933`) 的 sdist 分支才调用 Session.python。`Environment::new` (`build/python.rs:239`) 读取 build/pip;提前为每个 pip 根都安装 build/pip 不合理。
- npm:`Session::npm` (`build/npm.rs:15`) 先展开户籍归档,`npm::requires_build` 为 false 在第 43 行前后返回。只有确需生命周期/native 检查才创建 Environment,读取 build/npm。
- 当前 npm 的任何需执行 hook 路径都加载 Python + native build pack;当前 Python 的任何 sdist 也加载完整 build/pip。若 PRD 的“确有必要”要求进一步区分纯 JS hook / 纯 Python sdist 与 native 编译,需要收紧现有 environment 合同,而不仅加 lazy ensure;不能声称已做到逐个原生编译器按需。
### 当前锁记录什么、未记录什么
| 记录 | 源码依据 | 能力/缺口 |
| --- | --- | --- |
| LockedArtifact | `libs.rs:238` | target/path/bytes/sha256;path 是生成的逻辑路径,不是下载 URL |
| RuntimePack | `libs.rs:247` | name/version/sha256;运行时元数据从已签名版本读取 |
| LockedLib | `libs.rs:255` | 精确 spec、依赖、runtime、artifacts、schema、build receipt identity |
| LockFile | `libs.rs:267` | libs/workers/go_sumdb/npm/builds/packages;decode 要求规范字节与当前 TOOLCHAIN (`353`) |
| npm Environment | `registry/npm.rs:73` | 每个 Worker 独立 roots、实例路径、owner archive/prefix、edges、omission、build id |
| build Receipt | `build.rs:52` | roots/sources/graph/runtime/aux runtime/tools/frontend/Python backend/dynamic deps/递归依赖锁/output |
| LockedPackage | `packages.rs:75` | name/version/zip sha256/bytes/精确依赖/manifest sha256;来源在 setting 中已有 registry |
普通 PyPI wheel filename/URL 在解析后丢失(`registry.rs:905`);npm dist URL/SRI 未持久化(`988`);Go ZIP 地址可由已锁 spec 按现有 go_path 规则导出(`1121` 附近)。不改锁格式的恢复可查询**已锁精确版本**的 metadata 并仅选匹配锁 SHA/长度的文件,绝不重新选择版本或依赖;若文件撤下或变字节,明确失败。下载仍通过现有官方源/redirect/长度策略。
构建产物不是远端 registry 文件,必须优先从共享 cache 恢复;缺失时用固定 receipt 重放并比对锁定输出 SHA/长度,不能把新输出写回锁。
### 锁恢复的完整最小流程
1. install 参数禁止 specs,保留明确 target 选择。读且保存原始 setting/lock 字节;无锁立即报错;`LockFile::decode` + `doctor` 校验。将 install 纳入 `ProjectMutation::for_command` 的稳定互斥锁 (`mutation.rs:13`),不调用 setting 或 lock writer。
2. Package 必须先恢复:从已有 registry 的 `/v1/packages/<name>/<version>.zip`(`packages.rs:467` 的现有格式)取**锁定** ZIP,以 lock 摘要/长度验证并发布共享 artifact cache;不读版本索引、不选版本。然后复用 `owned_files_with` (`726`)、`validate_locked_roots` (`811`) 核对 manifests、依赖、源码归属和本地冲突。
3. 收集 config Lib、Package manifest Lib、源码 Worker 合同,验证锁 roots/closure;现有 `prepare` 只查声明包含性,不拒绝无主锁 libs。可借 `retain_locked_libs` (`2072`) 的闭包投影与原锁比较(不发布),同时核对 workers;注意 npm receipt 的原始图与 remove 后视图允许不同,不误判合法离线 remove 结果。
4. 仅为锁中实际 runtime 及 Worker ensure 对应版本/target 扩展,然后比对 RuntimePack;目标错配先报错,不替用户切换锁。对 fixture 条目复用内置字节与完整 metadata 校验。
5. 实现 `restore_locked` 的精确归档恢复,接受 `RegistryTransport`、`ArtifactStore`、build Inputs,便于 fixture 注入。按 SHA/bytes 查缓存,真实 miss 才取精确版本 metadata/归档。Go 使用锁中 `go_sumdb` 验 ZIP,不调用新的 MVS/checkpoint 解析。
6. 对缺失的构建产物递归恢复 receipt.sources 和 receipt.dependencies;验证 frontend、tools、runtime identity;通过同一个 sandbox/environment 实现固定重放。Python 重放使用锁定 backend/static+dynamic 依赖,不调用 `build_requirements`;npm 使用锁定实例图与已记录 optional 结果,不再进行 semver 解析。
7. 恢复后复用 `embedded_resources_for_target` 验最终产物,确认 setting/lock 原字节未变。任何失败保留已存在可用数据;新增正确 cache 项可留作重试复用。
### 必须正视的重放缺口
- `Session::python` (`build/python.rs:37`) 在 73/94 行调用 resolver.build_requirements,直接重用会重新解析,违反 install 合同。应提取固定依赖的执行阶段,供首次解析和锁重放共用。
- Python receipt source 被写成 `build/source/<hash>/source` (`python.rs:144`),没有 filename/格式;`source_files` (`196`) 需要 `.tar.gz` 或 `.zip`。可用 receipt 根的精确 PyPI metadata 按 source hash 找回文件名,但若 metadata 不再包含该源,必须报缺失。
- npm `sources` 在 optional 构建失败剪枝**前**采集 (`build/npm.rs:46`),receipt.graph 在 `prune_failed` **后**保存 (`72/87`)。失败节点 spec/owner 可能已丢,sources 只有散列路径,故当前 receipt 不保证可以完整重放原环境;不能凭摘要路径猜原包名。
- 若需要对新生成锁完整恢复,应在首次解析时保存 source locator/filename 与 npm 原始执行图(不同于最终消费图),并在 doctor/identity 中校验。不要添加旧格式兼容分支;按仓库“新语言直接迁移合同”规则迁移 fixtures/callers。已有锁缺最终产物且缺恢复信息时,明确说明不可恢复,不能静默 resolve。
- 即使输入齐全,任意第三方 hook/wheel 打包不保证字节确定性。重放输出必须匹配原 SHA,否则明确失败;没有远端保存原产物的机制就不能保证所有第三方构建永远能在全新机器复现。PRD 的精确恢复应以这一合同验证,不能以“版本相同”代替“字节相同”。
- `ManagedArtifactStore::get_exact` (`libs.rs:893`) 调 `artifact_get(...).map(Some)`;当前 miss、损坏、IPC 失败都 Err。`service.rs:327/515` 未提供 typed miss。必须增加明确 absence 结果或专用有界 existence/read 协议,不能 `Err => 下载`、不能匹配错误文本。缓存损坏和 service 不可达应继续失败。
### target add 与 CLI
`main.rs:435` 的 Lib operation 白名单和两个 USAGE 都需 install;launcher `project_root` (`launcher.rs:174`) 已识别任意 lib operation,可原样按项目版本转发。
`dever target add linux-aarch64` 没有 root 参数,应在 launcher dispatch 使用当前选定的 active 版本并调用 extension owner;若期望 cwd pin,则需要与主设计明确一致,不能悄悄扩大既有 project_root 行为。它仅准备 target runtime/sandbox;第三方 ARM Lib 仍 `lib ... --target linux-aarch64`。
Python sdist/npm hook 在非 host target 上由 `build::require_execution_target` (`build.rs:13`) 明确拒绝,需要匹配隔离执行环境或完整目标产物。target add 不能解除这个约束。Go runtime 则支持 host tools + target stdlib。
### 最近的测试夹具(本次未执行)
- `test/dever-cli-tests/external_libs.rs:331/400/418`:LocalRegistry、FixtureArtifactStore、三生态精确归档;`:451` 目标选择;`:1333` 离线确定性;`:1397` setting 不变;`:1469` 错配配置;`:1508` Worker 合同;`:1649` 无 Lib Worker。
- `test/dever-cli-tests/external_libs/build.rs:241`:不兼容 sdist 在装工具前拒绝;`:260/359` backend fixture / PEP517 hooks;`:422` 官方 sdist 为显式重测试,不默认运行。
- `test/dever-cli-tests/external_libs/npm_build.rs:68`:完整固定 receipt;`:264` 不重跑 hooks 的锁图投影;`:421` optional 失败/bin/offline remove;可增加记录请求次数的精确 install 用例。
- `test/dever-cli-tests/packages.rs:121/174`:注入 transport/store、传递 Package→Lib;`:621` 移除不请求 registry;`:725` 原 setting 字节回滚;`:909` signed managed 全链路(重验收,不默认执行)。
- 新定向验收应覆盖冷 cache install 后锁字节不变、metadata 新增更高版本仍不选、Package→managed Worker、空 specs/无锁/声明漂移、typed miss 与损坏差异、固定 Python build deps、npm optional 原执行图、输出摘要不一致失败、ARM mismatch、已缓存构建输出不加载 build extension,以及普通 run/build 绝不发 ensure/download。
### 建议定稿的数据合同与实施所有权
当前源码实际是 `LOCK_FORMAT = "dever-lock-v5"` (`libs.rs:25`),部分 spec 文案仍写 v2;本次直接升级 **dever-lock-v6**,无旧格式 fallback。建议单一、最小模式:
```text
LockedArtifact += source: Option<RegistrySource>
RegistrySource = { ecosystem: Ecosystem, locator: String, filename: String }
Receipt.dependencies -> Receipt.inputs: Box<LockFile>
```
`source` 对 registry 原始归档必填,对最终本地构建 output/fixture 可为 None;locator 是受现有 RegistryTransport 官方 origin/path 策略约束的精确地址,filename 只允许单文件名并承担解包格式选择,不从 URL query 猜格式。SHA/长度/target 沿用同一 LockedArtifact,不引入第二份内容身份。既然只接受 v6,source 必须成为已知字段,不需要兼容性 serde default;可序列化为 null。receipt 没有独立外部文件,**锁 v6 就是其 schema 版本**,不要再加无独立生命周期的 receipt 格式版本。
`inputs` 复用现有 LockFile:Python 为固定 build requirements 的精确递归锁;npm 为剪枝前 `libraries + npm graph`,图中 build=None,inputs.builds 为空,彻底避免自身 receipt 环。当前 receipt.graph 继续保存完整构建结束后的结果图(包括 prune 结果),供离线消费者与 `remove` 后投影使用。`sources` 保留为执行输入摘要列表并由 doctor 确认等于 inputs 的原始归档集合(Python 为单 sdist,build requirements 另在 inputs)。npm receipt.input 图不可被 remove 剪枝;最终 lock.npm 可以投影,原 receipt 保持不变。
实施所有权建议:
| Owner | 文件/API | 验证责任 |
| --- | --- | --- |
| extension/cache worker | toolchain extension owner、service/cache;ensure/read/list 与 `artifact_get_optional` typed miss | 签名、只读缺失/损坏区分、跨 UID、并发、失败原子性 |
| libs integration worker | libs.rs、main.rs、packages.rs、mutation.rs;明确 preparation policy、`install_locked`、Package exact restoration | 公共命令、Package 先恢复、Worker 提前准备、锁字节不变、离线边界 |
| registry/receipt worker | libs/registry.rs、build.rs、build/python.rs、build/npm.rs;v6 source、`restore_locked_artifacts`、`Session::replay` | 固定来源/输入、拒绝重新解析、嵌套依赖、输出 hash 不同失败 |
这些是逻辑所有权,可由同一 implementer 串行完成;`libs.rs` 类型/API 应由主实现者统一修改,避免多个 worker 同写。
具体公共/内部接点建议:
```text
toolchain::artifact_get_optional(layout, sha256, bytes) -> Result<Option<Vec<u8>>, String>
packages::restore_locked(project_root, lock, transport, store) -> Result<(), String>
libs::restore::install(project_root, target, preparation_inputs, transport, store)
-> Result<PreparationReport, String>
registry::restore_artifact(source, artifact, transport, store) -> Result<(), String>
build::Session::replay(receipt, store, signed_runtimes) -> Result<(), String>
```
`Session::replay` 绝不接收可解析版本的 RegistryResolver;将 Environment.run 中只用到的 store/runtime 提取成参数,首次 resolve 与 replay 共用原隔离执行器。Python inspect/requires 若执行,只用来比对已锁 backend/requirements,不能更新 inputs;metadata/wheel 阶段沿用现有检查。npm 执行 input 图,验证产出的 optional outcomes/native entries/rejections/结果图及 output SHA 与 receipt 相等后 publish。先完成全部验证再发布最终 output,不能先 publish 后发现不一致。
最小可测直接路径:现有 `build.rs:260` 的内联 backend fixture 无网络包管理器,验证固定动态 build requirements;`npm_build.rs:68` 固定安装收据与 `:421` optional 生命周期 fixture 验证原始图;在内存/目录 ArtifactStore 清空最终 output 后重放,两次字节一致。另加 hook 有意生成变化输出的 fixture,要求明确失败且锁字节保持。真实 C extension/node-gyp 仍复用现有显式 native fixture,不能把纯脚本 replay 通过报告成原生编译验收。
### External references
未查外部网络;本研究以仓库实现为准。协议事实来自现有代码:PyPI PEP440/508 + wheel、npm semver/SRI/实例图、Go proxy/MVS/sumdb、PEP517。版本绑定以 lock.TOOLCHAIN 和 signed RuntimePack/pack::Descriptor 为准,不假定系统 Python/Node/Go 版本。
## Caveats / Not Found
- 未实现任何功能、未运行测试/build/download、未修改产品或 specs。
- Extension catalog/IPC 的最终结构由发行路径研究和主代理决定;本文提供实际 caller 需求,不重复设计签名/安装 owner。
- 现有锁可精确获取大多数普通 registry 归档,但并非所有构建收据都包含完整重放信息;这是当前实现完整性的实际缺口,不是通过更多 retry 可解决的问题。
@@ -0,0 +1,101 @@
# Research: 精简发行、签名扩展与机器更新
- Query: 核对现有签名发行、bootstrap、共享机器资源与更新契约,给出最小完整拆分方案。
- Scope: mixed;源码只读,外部仅查解码 API 文档。
- Date: 2026-10-04
## Findings
### 现状与文件归属
| 文件 | 归属与证据 |
| --- | --- |
| `crates/dever-cli/src/toolchain/release.rs` | `ReleaseManifest`(74)只有 format/version/platform/artifacts;`MachineManager` 安装(293)、更新(310)、只读 core(437)、编译租约(470)、签名验证(579)、文件验证(616)、安装权限(968);稳定 `install.lock` inode(713)。 |
| `crates/dever-cli/src/toolchain/release_source.rs` | 官方 URL/重定向白名单(16、119)、元数据先验签(184)、同版本清单字节不变(213)、有界 gzip 下载(223)、catalog(250)、严格 USTAR 文件白名单(280)、NOREPLACE 发布(343)。 |
| `crates/dever-cli/src/toolchain/packaging.rs` | 固定 author 输入与签名;assemble(141)将 native、生态、sandbox、build 全部加入同一清单(202–234);必须在此按语义分类,不在压缩脚本根据随机路径猜测归属。 |
| `toolchain/packaging/{ecosystems,builds,sandbox,bootstrap}.rs` | 各类资源本身的语义校验与打包复用点;bootstrap(18)已有独立 ELF loader closure。 |
| `sdk/release-assets.py` | 所有清单 artifact 输出一个 deterministic gzip USTAR(create);目录发布使用 renameat2 NOREPLACE(publish)。 |
| `skills/scripts/install.py` | Python/OpenSSL 独立锚定公钥;authenticate(79)先验签,copy_artifact(129)精确字节/SHA 校验,payload(148)严格 tar 流,最后执行 bootstrap/dever。 |
| `toolchain/bootstrap.rs` 与 `bootstrap/transaction.rs` | 固定 bootstrap 系统落点、可信 key pin、崩溃恢复;SERVICE(19)仅允许写 state/cache/run,不允许服务写 versions 或新顶层目录。 |
| `toolchain/service.rs` | IPC Operation(100)只有 Status/Clean/ArtifactPut/ArtifactGet/Compile;内核 UID 认证(440),外 UID 可编译/资源缓存,不能 Clean;socket 0666、8 workers(34–36、154)。 |
| `toolchain/service/compile.rs` | compilation 租约、cache identity(74–86)、verify_pack(120)逐项验证所选 runtime 文件属于签名 manifest,cache hit 前也检查。 |
| `toolchain/runtime_pack.rs` | load_manifest(99)接受资源根目录,内部追加 runtime/<platform>;公开 validate(142)、RuntimePack::load(173)。 |
| `crates/dever-cli/src/compile.rs` | daemon 子进程依然在 worker(149)用 compiler_directory 加载 runtime;仅改 daemon 的 verify_pack 不够。 |
| `crates/dever-cli/src/libs.rs` | InstalledRegistry(709);tools(726)、runtime(797)、signed_artifact(823)、sandbox_resources(841)直接读版本根与根清单。 |
| `toolchain/cache.rs` | CacheStore 根实际为 cache/native(118),其中 ArtifactPut 单文件上限 64 MiB(81);不能用此 opaque artifact 上传接口安装 256 MiB 运行包。 |
| `toolchain/launcher.rs` | install/update 先下载后调用 MachineManager(27);当前 update 仅 core+skill,target 命令尚不存在。 |
现有清单并非全目录严格白名单:verify_artifacts 验证声明文件,core_libraries 对 lib 目录另有精确 closure 检查。拆分后不能把“目录存在”或只读 root metadata 当作签名证明。所有消费者仍需验证所属声明和文件字节。
### 建议的数据契约:一个签名根清单
将现有根清单明确升级新格式,保留 `version/platform/artifacts`,增加有界 `extensions`。`artifacts` 仅基础必需项;`extensions` 每项为 `{kind, target, artifacts}`。enum `ExtensionKind = Runtime(Ecosystem) | Build(Ecosystem) | Target`;身份为 `(version, host_platform, kind, deployment_target, signed_catalog_sha256)`,内容身份可对该项规范化完整描述计算 SHA-256。根签名覆盖所有扩展文件完整 path/bytes/sha256,不需要第二套扩展密钥或可变 unsigned receipt 作为信任来源。
基础内容:core、LLVM 完整 private closure、本机四 profile runtime、host sandbox、bootstrap、skill/templates。Target(ARM) 包含 ARM native 四 profile/CRT 与 ARM sandbox。Runtime(pip/npm/go,target) 与 Build(pip/npm,target) 独立;Go runtime 已包含 host 工具和 target stdlib,不强造 build/go。无基础文件与扩展间路径重叠,也无扩展互相路径重叠。
根清单 validator 统一校验版本/host、枚举目标组合、重复 ID、规范路径、lowercase SHA、数量/字节溢出、每包上限与全部描述上限。按固定类型限制 logical path:runtime/<ecosystem>/<target>、build/<ecosystem>/<target>、Target 对应 runtime/<target> 与 sandbox/<target>。防止扩展声明覆盖 core、lib、bootstrap、skill 或另一个 target。元数据顶层需 deny_unknown_fields;Python 同步语义,不维持兼容分叉。
外部 asset 名从固定 enum 计算;客户端与 manifest 不传任意 URL。每包一个 tar.zst;基础清单和签名单独发布;bootstrap 解码器作为原始文件单独发布并由根清单绑定。先签名固定原始内容,再压缩;确定性 USTAR 排序、mtime/uid/gid 和完整文件集继续成立。
### 扩展存储、接口与权限
推荐 `/opt/dever/cache/extensions/<version>/<catalog-sha>/<kind-target>/`;位于当前 service 可写范围内,和 `cache/native` 的可清理缓存分开。扩展先在专用 owner-private staging 中完全解压/验签/校验语义,fsync 文件和子目录,再 NOREPLACE rename 到最终路径。终态目录 0755、数据 0644,root-owned、不可被组/其他用户写;无需把 /opt/dever/cache 或 state 改成 0700。终态存在时重验内容而不是静默覆盖;失败仅清理自己 staging。manifest 摘要不同但版本相同必须失败,不创建并行“修正版”身份。
```rust
enum Operation {
// 现有操作……
EnsureExtension { version: Version, extension: ExtensionId },
}
struct ExtensionId { kind: ExtensionKind, target: BuildTarget }
// 网络/落盘仅 daemon 或拥有机器写权限的更新 owner 调用。
fn ensure_extension(layout: &Layout, version: &Version, id: &ExtensionId) -> Result<(), String>;
// 只读;不得打开 root-only install.lock,也不得下载。
fn resolve_extension(layout: &Layout, version: &Version, id: &ExtensionId) -> Result<VerifiedExtension, String>;
```
IPC 只接受已安装版本与其已验签目录声明的有限扩展,返回成功/内容身份而非用户指定路径。复用内核 UID/admission 和严格官方 HTTPS 下载,按请求限时、压缩/解压字节和数量限额;拒绝 caller 提供 URL、任意 filesystem path、payload 或 trust key。没有资源时 readonly resolve 返回准确 `dever lib install ...` 或 `dever target add linux-aarch64` 准备命令;run/build/check 不隐式进入 ensure。
采用一个 `SignedResources` 只读 owner,负责 root catalog、路径归属和已安装 extension 定位,供 InstalledRegistry 与 native pack 共用。`read_artifact(logical_path)` 与 `artifacts(prefix)` 只看到选定基础/扩展文件;避免构造 unsigned merged ReleaseManifest。RuntimePack::load 接收其实际资源根(base root 或 Target extension root),保留 logical path 到签名 artifacts 的逐项绑定。
SignedResources 需同时接入 libs.rs runtime/tools/sandbox_resources、service/compile.rs verify_pack、compile.rs worker RuntimePack::load。LLVM 动态库仍从 core 根加载。daemon BuildIdentity 必须包含所选 target pack 的签名/内容身份;不要让未使用扩展改变本机编译 cache identity。cache hit 仍重验所选 target pack。
### 更新与原子性
在同一个安装事务 owner 下读取 active 版本和其已安装扩展 ID 集合,验证新根清单有对应完整定义,下载并准备新 core+skill+这些扩展,最终重验后才 append active-version。失败保持旧 journal、旧 core 和扩展;已完整准备的新 immutable bytes 可留待重试复用,不声称更新成功。不自动安装新清单里所有扩展。
扩展选择直接由严格校验后的已发布目录集合导出,无需增加一个独立可漂移 selection pointer。若更新期间允许并行 ensure,必须在提交前锁内重新读取旧 active 扩展集合并补齐;更简单是将 ensure 与 update 的集合采样/发布串行化,避免丢失更新期间新增的扩展。沿用现有持久 inode lock,但不能在持有 exclusive lock 时递归调用再次 acquire 的公用 API;拆 locked 内部路径。当前锁为 try_lock,冲突会明确失败;如需“并发两项目都成功”应有限等待并在获锁后重验,不引入无限等待。
私有 staging 与 release.cleanup_staging 的全目录清扫不能冲突:若沿用 cache/staging,所有操作必须持同一安装锁;独立下载阶段则必须独占子树并禁止被旧 cleanup 删除。cache clean 目前只清 cache/native,保持其不删除 installed extensions。卸载版本时同安装锁删除对应扩展命名空间,active 保护不变。
当前 `dever update` 不更新机器 `/opt/dever/bin/dever[d]`,只更新版本目录/active。新资源 IPC 必須在首装 bootstrap launcher/daemon 中就存在;后续若改变 IPC,旧 daemon 兼容性是单独的 bootstrap 生命周期问题,不能假设 active core 更新自动重启了新服务。
### Zstandard:统一 Rust 解码,Python 验证后执行已有 launcher
推荐 zstd crate 的安全 streaming wrapper,静态编入发行时所需 decoder library;不要手写 C FFI 或 ctypes 依赖宿主 libzstd。Rust release downloader 与 launcher 隐藏 extraction 入口复用一个 codec/archive 模块:固定 `window_log_max(27)` 对应 128 MiB、压缩输入上限、解压输出上限、精确 frame 结束与 EOF 检查。不得仅 tar 遍历到结束标记就成功,必须排空/校验 zstd frame 尾部,拒绝截断与尾随额外数据;默认 Decoder 会连续解多个 frame,单 frame 策略需显式实施。
首装 Python 保留 OpenSSL 签名锚:下载/验证根 manifest → 从基础 artifacts 的固定 bootstrap/dever 与 bootstrap/lib/* 集合,按 digest 命名的 raw assets 下载全部 launcher closure → 精确大小与 SHA 验证、权限落盘 → 以空环境、绝对路径执行隐藏 `--dever-extract <owned-config-root>` → launcher 再验证根清单签名并调用共享 Rust USTAR 解包 → 完整已校验后执行 bootstrap 安装。配置与 trust key 仅放 root-owned scratch,不从应用读取。raw helper 文件与 payload 目标必须是两个目录,避免 create_new 冲突。需要 subprocess timeout 与失败后 kill/wait,不能把解包失败当成可继续安装。
现有 staged manifest 声明 `bootstrap/lib/libgcc_s.so.1`(`target/release-0.1.0/assets/dever-linux-x86_64.manifest.json:27`)。因此直接下载裸 launcher 不成立;但按主 agent 收敛方案,额外发布已签名 raw launcher + 完整小型私有 lib closure 后,复用 launcher 优于新 decoder bin:没有额外执行文件/第二套 tar validator。raw asset 文件名由既有 SHA 推导,不能由远端任意 URL 或目录控制。作者阶段仍需验证 ELF DT_NEEDED、RPATH、完整私有 closure,确保 zstd 为静态且 LLVM 不被引入 launcher/daemon;Linux libc/loader 为已声明 OS ABI。Python 在执行前只能信赖独立签名和已固定路径规则,签名发行 maker 对 closure 的检查仍是必要发行门槛。
Python SDK maker 可以使用作者提供的 zstd 工具或编码库完成 deterministic streaming tar.zst;这属于 author 工具链,不把系统 zstd 加成最终用户前提。公共资产总大小应单独计入 raw bootstrap closure,而不是只报告主 tar.zst。
### External references
- [zstd Decoder API](https://docs.rs/zstd/latest/zstd/stream/read/struct.Decoder.html),本次页面为 0.14.0:Read streaming、single_frame、window_log_max;finish_frame 错误需要显式处理。版本选型应核对仓库 MSRV 并固定 Cargo.lock,本次没有安装或锁定依赖。
- 本地 SDK `target/backend-sdk/usr/include/zstd.h:107` 为 1.5.5;`:606` 说明 streaming window 上限控制、`:648` 提供 DCtx 参数 API。这是本地已有头文件证据,不代表最终打包采用此版本。
- GitHub zstd-sys Cargo.toml 页面读取失败;静态链接需在实施中核对选定 crate build 配置与产物 ELF,不能将本研究当作已验证链接证据。
### Related specs
- `.trellis/spec/backend/toolchain-and-library.md:23` compiler-relative runtime 与 daemon 签名闭包;`:27` bootstrap;`:84–96` release/skill/author/ELF closure;`:337–343` onboarding、native release、shared toolchain 定向验收。
- `.trellis/spec/backend/index.md`:本仓库是 Rust 语言编译器,不采用 Go Dever Model/Page/Service 规则。
- `.trellis/tasks/10-04-slim-distribution/prd.md`:离线 run/build、多用户共享、按需自动生态、target 命令、core+已装扩展更新、不改宿主服务。
## Caveats / Not Found
- 子 agent `task.py current --source` 返回 none;主 agent 已明确指定此任务与写入位置,未修改任务状态。
- 本次未下载发行/依赖、未运行构建/测试、未改产品文件/服务,也未读取私钥或授权凭据。仅查看公开解码 API 文档。
- 120 MiB 目标是已有压缩估算;codec 与新正式优化 core 会改变最终数字,尚无本次测量。
- 精简需同时调整 package/Lib 显式准备策略:另一研究分支已发现 `source_workers_with_packages` 在 resolve_project 前读 runtime;不能只在 resolver 内 ensure。remove/doctor/check/run/build 必须 readonly。
- 更新携带范围建议 active 版本已安装选择;若产品要求机器所有历史 pinned 版本的 union,应在设计明确,不应默默给新版本安装历史上任何扩展。
- 大包首次安装、损坏重试、多 UID 同时 ensure、更新失败仍运行旧版、ARM cache hit 校验、decoder 超大 window/截断/尾随数据均需定向验收;本研究没有执行验证。
@@ -0,0 +1,26 @@
{
"id": "slim-distribution",
"name": "slim-distribution",
"title": "Dever 精简发行与按需工具安装",
"description": "将基础包缩至约 120 MiB,拆分签名扩展并完成 lib install、target add、更新及实际发行验收",
"status": "completed",
"dev_type": null,
"scope": null,
"package": null,
"priority": "P2",
"creator": "Antigravity",
"assignee": "Antigravity",
"createdAt": "2026-10-04",
"completedAt": "2026-10-05",
"branch": "codex/slim-distribution",
"base_branch": "main",
"worktree_path": null,
"commit": "4fda7c8c1a33b843e2fca219cb3bc95c09471716",
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [],
"notes": "精简发行实现和本地验收完成:112.04 MiB基础包,58项定向、13阶段实包、4阶段本地更新事务通过。核心4fda7c8、skill27ac8f2及v0.1.1标签已推送。GitHub API未登录,二进制Release未上传、线上更新未跑;该外部发布待办不标为通过,详见implement.md与target/release-0.1.1/release-state.json。",
"meta": {}
}