Files
qinglong/docs/adr/ADR-0206-direct-init-managed-release-startup-receipt.md
T

158 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-0206:直连 Init-managed Release 与有界启动凭据
- 状态:Accepted
- 日期:2026-07-29
- 关联 RFCQL-RFC-0001 D-86、D-87、D-175、D-194、D-195、D-196
- 关联 ADRADR-0088、ADR-0178、ADR-0194、ADR-0204、ADR-0205、ADR-0362、ADR-0363
## 背景
ADR-0205 用 Node 前 POSIX wrapper 把 Linux kernel uptime、systemd/OpenRC 和正式
application `active` 事件放进同一个新 boot。它诚实地保留了
`direct_release_unit_without_evidence_wrapper`wrapper 改变了 production
descriptor 的主进程和进程树,不能证明最终直连 Node unit 具有等价行为。
只依赖 stdout/journal 不能同时覆盖 systemd 与 OpenRC,也会受日志持久化、轮转和
墙钟影响。给低配路由器增加日志 daemon、watcher 或 append-only readiness journal
又会增加常驻内存、唤醒和闪存写入。
## 决策
### 1. 启动凭据属于现有 Local Application 组合层
不新增 workspace package。`@qinglong/local-application` 在 Linux 返回正式
`active` 后、输出 active JSON event 前发布:
```text
<absolute-config-path>.active.json
```
该文件是 `qinglong/local-application-startup-receipt@v1`,只包含:
- instance/Profile/AI deployment status
- 当前 boot ID 与 active 时的 `/proc/uptime` 毫秒值;
- 当前 PID、`/proc/<pid>/stat` start ticks
- `/proc/<pid>/exe` 的 canonical Node path 与 Node version
- domain-separated SHA-256。
它不包含配置内容、Secret、数据库路径、Project/User/Run 数据或插件材料。非 Linux
进程不发布该文件。
### 2. 状态文件有界且每次激活只替换一次
凭据最大 4 KiB、mode `0600`、single-link。publisher 要求 config parent 为当前
UID 控制且 group/other 不可写,使用同目录唯一 deterministic `.stage`
1. stage 不存在时以 `O_EXCL|O_NOFOLLOW` 创建;
2. crash 遗留 stage 只有在 owner/mode/link/inode 精确可信时才复用;
3. 完整写入后 `fsync` stage
4. 重新核对 parent identity
5. 以 rename 原子替换 current receipt,并复验 final inode/mode/link/size
6. directory fsync 在不支持的文件系统上保持 best effort。
因此每次成功激活最多产生一次小文件重写,不扫描目录、不追加历史、不启动 timer、
watcher、listener 或后台清理。它适用于 128 MiB Edge,也可被 Standalone/Cluster
节点的宿主采集;whole-device/FTL 写放大仍必须由物理门测量,不能从 4 KiB logical
上限推导。
Linux 上凭据发布失败会阻止正式 active event 并让进程失败关闭。旧凭据在新进程
启动期间可能暂时存在,所以消费者必须同时核验 boot ID、PID、start ticks 和实时
进程,不能把“文件存在”当 readiness。
### 3. D-196 使用完全直连的 production descriptor
非 package 命令 `evidence:physical-edge-direct-service-start` 提供:
- `inspect`:复用 exact 10-package AI-excluded release closure inventory
- `prepare`:通过正式 `prepareLocalDeployment` 生成 fresh Edge
systemd/OpenRC descriptor`ExecStart`/`command` 直接为 exact Node binary +
正式 local-application CLI + production config
- `resume`:新 boot 内复验 receipt、init、实时进程、artifact 和预算。
2026-08-11 起,prepare 不再输出可绕过产品权限模型的 root install/enable plan。
它以当前 Owner UID 通过正式 `prepareLocalServiceManagerIntent` 发布
`install-enable-start + fresh` intent,并把 action ID、intent digest、Owner
intent/outcome path 与固定 root controller root 写入 session。stdout 只提供固定
shape 的 root bridge commandoperator 必须把该 command 写成 root-owned `0600`
私有文件并显式运行独立 `ql3-service-bridge`recorder 自身仍绝不取得 root、安装、
enable、start、reboot、stop、disable 或清理 authority。
service name 与产品 bridge 一致固定为 `qinglong3`,不再为证据生成另一套随机 unit。
resume 在新 boot 采集 init/receipt 前,先以原 Owner UID 调用正式
`consumeLocalServiceManagerOutcome`,重新验证 intent、outcome、descriptor/config、
UID/GID 与 manager observation,并要求 outcome 为 `active`。最终 report 同时绑定
bridge action/intent/outcome/observation digestqualification 增加
`owner_intent_root_service_bridge_owner_outcome`;仅有 root manager exit code、已安装
unit 或当前 receipt 均不能替代该链路。
### 4. 同一 Linux 单调时钟域决定时延
resume 直接从 Linux `/proc/self/auxv` 读取 `AT_CLKTCK`,把 receipt 的 Node
start ticks 转换为 `serviceStartBootAgeMs`,并以 receipt 的 uptime 得到:
- `activeBootAgeMs` / `bootToActiveMs`
- `serviceStartToActiveMs`
systemd 还必须满足 loaded/active/running/enabled、exact FragmentPath/MainPID
并让 `ExecMainStartTimestampMonotonic``/proc` start ticks 在 50 ms 内一致。
OpenRC 必须 active、属于 default runlevel,且 Node 的实时父进程 executable/hash
是 prepare 时绑定的 `supervise-daemon`。两者都必须复验 Node UID、PID/start
ticks、`/proc/exe` 和完整 argv。
receipt/report/importer 都重新计算 exact shape 与 digest。相同 UID 或 root 仍可
伪造本地事实,所以该协议还要求 root-owned exact installed descriptor、不同 boot、
零虚拟化指标和实时 init/process identity;它不是远程证明或签名 attestation。
### 5. 结论保持候选且只关闭 wrapper 等价缺口
通过的报告增加:
`kernel_boot_to_direct_init_managed_release_application_active`
统一 importer 此时移除
`direct_release_unit_without_evidence_wrapper`,但继续保留:
`firmware_and_bootloader_power_on_to_linux_kernel_clock`
报告永久 `supported:false`。它仍不证明 exclusive cold cache、active 前 RSS/I/O、
stdout active event 的后续交付、突然断电、Compose、
Standalone/Cluster 或 release archive signature。
ADR-0363 后续增加与 start report 精确配对的独立 direct service stop report:它要求
Application SIGTERM shutdown receipt、Owner stopped outcome、旧 PID/start identity
消失以及 init inactive/still-enabled。只有导入该独立报告才关闭
`init_managed_graceful_application_stop`direct start 本身仍不能冒充 stop 证据,service
disable 也继续不在本 ADR 范围内。
## 验收证据
- startup receipt package 专项:macOS 3 pass/1 Linux 条件 skip
- 只读、无网络、cap-drop、no-new-privileges、128 MiB/64 PID 的 Node 24.18 Linux
容器:receipt `/proc`、真实 `AT_CLKTCK` 与 direct report 13/13
- 同一隔离 Linux 容器中的完整 local application process10/10,覆盖 real
headless runtime、CLI active、receipt PID 与 SIGTERM
- direct recorder manifest/CLI/init clock/receipt/session/report/importer
macOS 9 pass/1 条 Linux 条件 skipD-195 聚合回归 3/3,合计 12 pass/1 skip
- D-274 升级回归要求 session 固定 `qinglong3`、绑定 Owner intent/root bridge
outcomereport/importer 对缺失或漂移的 bridge digest/active outcome 失败关闭;
- 当前 Edge application artifact 仍为 exact 10 packages5,066,155 bytes、
629 files、91 loaded modules,低于 8 MiB/640 files/96 modules 门;
- PostgreSQL 18.4 arm64 HA 回归的 35 个具体 gate 与总 `passed` 全为 true
- workspace 保持 17 个 package,无新增生产依赖或常驻资源。
开发机没有真实 systemd/OpenRC PID 1,也没有执行 operator
root bridge/reboot/resume,因此尚未产生物理设备 direct report。Accepted 表示
协议与失败关闭实现完成;固定 systemd/OpenRC 路由设备采集仍是 release Gate。
## 被拒绝的替代方案
- **继续使用 wrapper 并称为等价**:主进程和进程树不同。
- **只解析 journal/syslog**:不能稳定覆盖 OpenRC、持久化策略和单调时钟。
- **append-only active log**:重启次数会变成无界闪存历史。
- **独立 readiness daemon/socket**:增加低配节点常驻内存、端口和 authority。
- **新增 startup-receipt package**:只有现有 application 一个生产者/消费者边界,
会重新制造单文件 package。
- **自动安装、enable 或重启**:扩大宿主机破坏 authority并绕过人工审查。
- **保留旧 recorder 的直接 root install/enable plan**:会让物理发布门绕过
D-274,得到一份启动成功但无法证明由产品 bridge 安装的报告。