设计原则
SOW 首先不是一个“元数据生成器”,而是一个所有权与状态迁移系统,只是它的输出恰好是 APT 与 RPM 仓库。下面这些原则让整套系统保持可推理。
每个持久事实只有一个主人
每类持久事实都只有一个作用域与权威:
| 事实 | 所有者 |
|---|---|
| 包体与软件包身份 | Repository |
| Desired 成员关系与 Built 状态 | Repository |
| Generation 与 Changeset | Repository |
| 发布尝试与已应用 Checkpoint | Repository + target prefix |
| 远端 inventory、grace 与删除证据 | Repository + target prefix |
状态不会在 Repository 或发布前缀之间暗中共享。因此同一个包可以在不同 Repository 或 target 中各存一份;这是有意为之:本地去重不能制造分布式所有权。
正典数据与可重建投影
pool/ 中的包体是正典数据;协议索引、架构视图、报告与兼容导出都是投影。只有当 SOW
能证明输入集合完整且所有权明确时,投影才可以重建;它永远不会成为包体的第二个主人。
由此得到一条简单删除规则:投影只能由创建并记录它的操作移除;正典数据只有在所有 live 与 retained owner 的可达性都计算完成后才允许移除。
公共树是交付单元
Repository 根由 pool/ + dists/ 组成;整棵树才是静态托管、复制、鉴权与发布单元。
某个 RPM 架构 leaf 可以被客户端消费,但它不是一个独立拥有状态的 Repository。
sow.yml、.sow/、锁、journal、凭据与恢复文件都是私有状态,绝不能随公共树对外服务。
包体做准备,指针做提交
发布顺序固定为:
包体 -> 不可变/校验和命名的元数据 -> 可变指针 -> 宽限期 -> 删除
包体与不可变元数据可以提前写入而暂不可见;repomd.xml、Release 或 InRelease 这样的
协议指针才是提交边界。只有新指针已经持久化、旧读者与缓存窗口已经关闭后,旧对象才可删除。
恢复服从持久证据
提交意图之前,如果精确 reconcile 能证明公共指针从未改变,操作可以放弃;提交意图之后 只能前向恢复。SOW 不猜测一次半完成发布“应该已经成功”,而是比较 journal、manifest、 checkpoint、供应商身份与公共树。
证据互相矛盾时操作必须停止。一次可见的拒绝,比仓库历史悄悄分叉更安全。
兼容性是一张矩阵
协议合规、普通客户端、镜像工具、对象存储布局、代理规范化与文件系统语义是不同问题。 SOW 分别记录它们,并用与结论对应的真实客户端或供应商验证。
因此 v0.2 可以为了 reposync 采用硬链接视图;0.3 也可以为了让远端每个包只存一份,
明确把默认 reposync 移到外部兼容导出中处理。
证据不会自动升级
规格不是实现,单测不是真实客户端结果,本地 Hugo 构建也不是公网发布。日期化结果始终绑定 当时的源码 revision、环境与版本;布局变化后,必须重跑对应门禁,不能把旧 PASS 直接继承。
非目标让模型保持诚实
0.3 不承诺跨 Repository 去重、重叠多写者、bucket 全局协调、任意第三方镜像工具兼容, 也不在供应商缺少原子条件删除时承诺安全远端删除。这些排除项属于安全契约,不是“尚未补完”。