# 编辑声明，保留文档：无损 Pigsty Inventory

> 为什么 pig inventory 将 YAML 语义与源字节分离，让局部编辑能够保留注释、顺序、锚点与格式。

---

LLMS 索引： [llms.txt](/zh/llms.txt)

---

> **决策日期：** 2026-07-18<br>
> **状态：** 已实现并随 [pig v1.6.0](/zh/release/pig-1.6.0/) 发布。<br>
> **当前参考：** [`pig inventory`](/zh/inventory/)<br>
> **范围：** 静态 Pigsty Inventory 的查看、局部编辑、校验、比较与安全写入。

## 决策 {#decision}

PIG 同时把 `pigsty.yml` 视为语义声明和人工维护的源文档。语义解析器负责判断 Inventory 的含义，
原始字节则决定它的书写方式。局部编辑只替换有边界的源范围，并在原子写入前重新解析完整候选文件。

这样可以避免 YAML 工具常见的失败模式：逻辑上正确的一次编辑，却悄悄重写整份文件的注释、键顺序、
引号、锚点、块标量或换行风格。

## 背景 {#context}

Pigsty Inventory 是长期存在的运维资产，包含拓扑、调优、凭据、注释、示例、锚点和本地有意义的顺序。
普通的“解析—修改—序列化”流程可能生成有效但无法审阅的差异，并改变运维人员没有选择的结构。

另一方面，没有语义校验的纯文本编辑又可能把无效或自相矛盾的配置写入磁盘。
设计必须同时获得源文件保真与整文正确性。

## 考虑过的方案 {#alternatives}

- **使用一个 YAML 序列化器完整往返。** 在真实 Pigsty 语料上，没有选定的序列化器能够逐字节保留完整源契约。
- **用正则表达式处理 YAML。** 引号、注释、别名、块标量和嵌套集合让纯文本语义判断不安全。
- **只编辑规范化生成副本。** 活跃 Inventory 属于运维人员，仍会与生成表示发生漂移。
- **允许替换所有节点类型。** 锚点、别名、标签与块标量需要比普通映射和标量更严格的处理。

## 契约 {#contract}

- 拒绝重复键与多文档 YAML；
- selector 只定位一个无歧义的声明片段；
- 语义解码与源范围发现是两项独立职责；
- 编辑从精确源 revision 开始，文件被并发修改时失败；
- 编辑片段只进行插入上下文所必需的规范化；
- 提交前重新解析并校验完整候选文件；
- 写入使用同目录临时文件、sync、rename 与目录 sync；
- 拒绝符号链接与不安全路径变化；
- 成功编辑后将含密 Inventory 权限收紧为 `0600`；
- 除非命令明确属于原始文本表面，诊断、diff、计划与结构化结果都不输出声明值。

## 影响 {#impact}

编辑器比普通 YAML marshal 更复杂；当无法证明源文件保真时，一些语法有效的片段也会被有意拒绝。
换来的结果是可审阅差异：未选择部分逐字节稳定，无效 YAML 无法落盘，并发修改不会被静默覆盖。

`show` 仍然明确属于可能含密的接口。坦率声明这个例外，比假设一个不完整的脱敏器能识别未来所有凭据键更安全。

## 验证与演进 {#verification}

根级 Inventory 契约与既有 CMDB 边界建立于
[`ba6e678`](https://github.com/pgsty/pig/commit/ba6e678)，实现落地于
[`ea43858`](https://github.com/pgsty/pig/commit/ea43858)。测试覆盖真实 Pigsty 配置语料、逐字节往返、
局部替换、受保护 YAML 形式、并发变更拒绝、原子写失败、selector、校验和无敏感值诊断。

后续重构移除了旧选项并分离校验阶段，但没有改变源文件保真模型。

## 当前状态 {#status}

静态 Inventory 仍是主要声明表面。selector、校验 profile、结构化输出与明确标记为实验性的 CMDB 桥接，
均以当前 [`pig inventory` 参考文档](/zh/inventory/)为准。
