Files
qinglong/docs/adr/ADR-0205-physical-edge-init-managed-service-start-evidence.md
T

142 lines
6.9 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-0205:物理 Edge Init-managed Service 首次 Active 候选证据
- 状态:Accepted
- 日期:2026-07-29
- 关联 RFCQL-RFC-0001 D-86、D-87、D-175、D-194、D-195
- 关联 ADRADR-0088、ADR-0193、ADR-0194、ADR-0204
## 背景
ADR-0204 已证明不同 Linux boot 中,最终 AI-excluded native application closure
可以从 recorder `spawn()` 到唯一正式 `active`,但 recorder 本身已经加载 Node
也没有经过 systemd/OpenRC。它因此仍把
`power_on_cold_node_and_service_manager_start_to_first_ready` 保留为 broad Gate。
完整 firmware 上电时间不能从 Linux 用户态可靠取得。`/proc/uptime` 从 Linux
内核时钟开始,不包含 bootloader/firmware;安全实现必须拆开这一边界,而不是把
kernel uptime 改名为 power-on latency。
## 决策
### 1. 新增非 package、无自动整机 authority 的三阶段记录器
根命令 `evidence:physical-edge-service-start` 提供:
- `inspect`:复用 ADR-0204 的 exact 12-package artifact 与 Node inventory
- `prepare`:创建 fresh Edge deployment、证据 wrapper、FIFO 和 digest-bound
session
- `resume`:只读核验新 boot、init 状态、进程身份和正式 active 后发布 report。
记录器不新增 workspace package、生产依赖、daemon、timer、watcher、端口或
Cluster import。它绝不执行 `install``systemctl enable/start``rc-update`
`rc-service start`、reboot、poweroff、stop、disable 或文件清理。
### 2. Operator 必须显式安装并启用 exact descriptor
prepare 使用正式 `prepareLocalDeployment`
- Profile 固定为 Edge
- service kind 由 manifest 固定为 `systemd|openrc`
- 仍使用 production renderer 的 User/Group、WorkingDirectory、resource limit、
SIGTERM、restart 和 hardening contract
- systemd 的 probe 目录位于 deployment root 内,满足
`ProtectSystem=strict + ReadWritePaths=<deploymentRoot>`
prepare 输出而不执行:
- descriptor source/destination 与 SHA-256
- `/usr/bin/install` 的逐参数 invocation
- `systemctl enable <unit>``rc-update add <service> default` 的逐参数
invocation。
session 精确绑定这些参数、目标 mode、service name、status manager 与 enable
executable/hash、wrapper hash、artifact/Node、UID、prepare boot 和所有 scratch
path。systemd 两者都是 `systemctl`OpenRC 分别是 `rc-service``rc-update`
operator 审查后以 root 安装/enable,再在工具外正常重启。resume 要求目标
descriptor 为 root-owned、single-link、exact mode/content。
### 3. POSIX wrapper 在 Node 之前建立时间锚点
证据 wrapper 是私有 `0700` POSIX shell 文件。它在执行 Node 之前:
1. 复验 exact `node --config <path>` 参数和已准备 FIFO
2.`/proc/sys/kernel/random/boot_id``/proc/uptime` 读取 boot/start
3. 以 noclobber 创建 `0600` start/event/stderr 文件;
4. 才启动 exact Node binary、正式 `@qinglong/local-application/dist/cli.js`
production config。
wrapper 逐行复制 application stdout。遇到同时包含正式 component/event/Profile/
AI status 的候选行时,立即读取同一 `/proc/uptime`,以 event ordinal 发布一次性
active record。resume 使用 Node exact JSON parser 重新验证整个 event log、唯一
active 和 ordinalshell substring 不能自行形成通过结论。第二个 active、已有
record、partial JSON、非零 stderr 或 boot/monotonic 逆序均失败关闭。
wrapper 不是旁路 daemon:它就是 evidence service 的 main process,转发终止信号,
并等待唯一 Node child。systemd 必须把 wrapper PID 报为 `MainPID`OpenRC 必须由
`rc-service status` 和 default runlevel 同时证明 active/enabled。
### 4. Resume 必须复验实时 service 与进程树
resume 在读取报告文件前要求:
- 与 prepare 不同且与 wrapper record 相同的 boot ID
- 当前 boot age、架构、文件系统、UID、Node 和 manifest 一致;
- `virtualizationIndicators` 为空,容器/VM 直接拒绝;
- artifact metadata、wrapper、manager 和 installed descriptor 未漂移;
- systemd `loaded/active/running/enabled`、exact FragmentPath/MainPID,或 OpenRC
active + default runlevel
- wrapper/node PID 仍存活,Node PPid 为 wrapperUID、`/proc/exe` 与完整 cmdline
精确匹配。
最后重算完整 artifact content。报告记录:
- `serviceStartBootAgeMs`
- `activeBootAgeMs` / `bootToActiveMs`
- `serviceStartToActiveMs`
- active event ordinal 和 live process start ticks。
所有三项时延都必须落在 manifest 的显式预算内。report 与统一 importer 都重新
计算 qualification,不能信任报告自带 `passed:true`
### 5. 结论继续保持候选与窄作用域
通过的报告增加:
`kernel_boot_to_init_managed_native_application_active`
并把 broad Gate 细化为仍未完成的:
- `firmware_and_bootloader_power_on_to_linux_kernel_clock`
- `direct_release_unit_without_evidence_wrapper`
报告永久 `supported:false`,并明确不证明 exclusive cold page cache/dynamic
linker provenance、active 前 RSS/I/O、service stop/disable、突然断电、Compose、
Standalone/Cluster 或 release attestation。证据 wrapper 将测得时延作为安全上界,
但它不是最终直连 Node 的 release unit;必须保留 equivalence Gate。
## 验收证据
- Linux recorder manifest/CLI/wrapper/session/record/init/report/POSIX
syntax/OpenRC executable split/virtualization/FIFO-child 契约 13/13
- importer same-device/current-boot/qualification 再裁决与 remaining Gate 细化
3/3
- importer 3/3Linux 专项合计 16/16macOS 为 12 pass/1 条件 skip
- exact Node 24.18.0 bookworm-slim digest 在只读 rootfs、无网络、cap-drop、
no-new-privileges、128 MiB/64 PID 下完成真实 FIFO、active ordinal 和 SIGTERM
wrapper smoke;该容器只证明脚本兼容,不是物理/init 报告;
- wrapper 静态门不含 reboot/poweroff/systemctl/rc-service/rc-update/sudo
- 实现不新增 workspace package、生产依赖或常驻采集资源。
macOS 开发机不能运行 Linux PID 1、`/proc` 和真实 enable/reboot,所以没有产生
物理报告。Accepted 只表示协议、采集器和失败关闭门已实现;固定 systemd/OpenRC
设备的 operator install/reboot/resume 仍是发布候选 Gate。
## 被拒绝的替代方案
- **使用 `Date.now()` 作为 power-on 时间**:墙钟可跳变,也没有 firmware 起点。
- **由 Node recorder 在 reboot 后启动 Node**Node 已被 recorder 自己预热。
- **自动安装/enable/reboot**:扩大整机破坏 authority,且不能保留人工审查边界。
- **只读取 journal 文本时间**:日志持久化、clock domain 和旧 boot 过滤不稳定。
- **把 wrapper descriptor 称为最终 release unit**:证据 shim 改变了进程树。
- **新增 boot-agent package/daemon**:增加低配 Edge 的交付和常驻成本。