mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-23 11:53:48 +08:00
feat(ql3): gate primary on shadow capture evidence
This commit is contained in:
@@ -239,7 +239,7 @@ Shadow Adapter 不得:
|
||||
|
||||
Shadow 转换仍必须遵守 ADR-0001。无法合法映射时追加 compat.transition_mismatch,不能强行覆盖终态。
|
||||
|
||||
当前 Alpha 切片对已审 Node worker origin 直接观察同一 ChildProcess 的 spawn、error 和 exit 事件,因此不依赖 Shell callback 才能形成基本终态。下述两级关联已补充 Shell callback、stop/cancel 和乱序/迟到回调;ADR-0448 又补充了监听前一次性启动恢复,ADR-0449 将其投影为 origin-bounded、版本化的差异报告与固定字段 metric batch。ADR-0450 再提供显式、只读、Profile-bounded 的闭合窗口终态审计;ADR-0451 已在 128 MiB router stress 与 256 MiB Edge release cgroup 中证明有界查询、SQLite 零增长和进程重启后的 Shadow-off 回滚。但 2.x RunningInstance 缺少可信 origin,因此这些证据只覆盖已写 Shadow Run 到 Legacy evidence 的一致性,不能单独证明 Legacy→Shadow 捕获率或替代正式 Primary gate。
|
||||
当前 Alpha 切片对已审 Node worker origin 直接观察同一 ChildProcess 的 spawn、error 和 exit 事件,因此不依赖 Shell callback 才能形成基本终态。下述两级关联已补充 Shell callback、stop/cancel 和乱序/迟到回调;ADR-0448 又补充了监听前一次性启动恢复,ADR-0449 将其投影为 origin-bounded、版本化的差异报告与固定字段 metric batch。ADR-0450 再提供显式、只读、Profile-bounded 的闭合窗口终态审计;ADR-0451 已在 128 MiB router stress 与 256 MiB Edge release cgroup 中证明有界查询、SQLite 零增长和进程重启后的 Shadow-off 回滚。ADR-0453 不再从 2.x RunningInstance 猜测反向分母,而是在默认 Legacy bridge admission 建立 process-epoch 守恒 token,并把 capture/startup、terminal 与 resource/rollback 三类低敏 source report 打包;rollout v2 loader 会独立重算 bundle 后才允许 manual Primary。
|
||||
|
||||
### 9.4 `next` Alpha callback 与 stop 关联
|
||||
|
||||
@@ -253,7 +253,7 @@ Shadow 转换仍必须遵守 ADR-0001。无法合法映射时追加 compat.trans
|
||||
6. 取消事实在 Legacy kill 前投递;同 worker 的后续 exit 排在取消之后。跨 worker 使用持久化定位器尽力关联,任何查询或写入失败都不能阻断 kill 或改变 2.x API 响应。
|
||||
7. 乱序 finished 可以从 queued/claimed 补齐 dispatching、starting、running 和终态;重复终态 callback、取消后的迟到成功 callback 不覆盖终态,也不追加重复完成事件。
|
||||
|
||||
这仍不是完整的 Shadow→Primary 门禁:ADR-0448 已提供启动后有界批量扫描、终态证据补齐、lost/abandoned 收敛和两事务 response-loss 修复;ADR-0449 已增加 startup 差异报表、固定低基数 metric batch 与可注入单次 collector;ADR-0450 已完成不伪造反向捕获率的闭合窗口 Shadow→Legacy 终态差异查询;ADR-0451 已完成 Profile-aware 资源压力和 Shadow-off 进程重启回滚。具体 exporter、Legacy→Shadow capture authority 和正式 Primary gate 尚未完成。后续能力不得让 edge 增加常驻 watcher 或无界内存队列。
|
||||
ADR-0453 已补齐 manual origin 的正式 Shadow→Primary 判定契约:process-local admission/capture/failure/pending 守恒、clean-shutdown 一次性 exporter、capture/startup + terminal + resource/rollback 自包含 bundle,以及 rollout v2 loader 的独立重算。它仍不会自动启用 Primary;目标实例必须产生真实 manual canary bundle,其他 origin 也必须独立评审。后续能力不得让 edge 增加常驻 watcher 或无界内存队列。
|
||||
|
||||
### 9.3 Shadow 写失败
|
||||
|
||||
|
||||
+2
-1
@@ -73,5 +73,6 @@ ADR-0450 已冻结闭合窗口的 Shadow→Legacy 终态审计语义,但只证
|
||||
|
||||
## 后续
|
||||
|
||||
D-360 仍须建立可信的 origin-scoped Legacy→Shadow capture authority,组合 observer failure/capture evidence 与本 ADR/ADR-0450 的结果,再定义正式 Primary gate。
|
||||
D-360/ADR-0453 已建立 origin-scoped Legacy→Shadow capture authority,并把 observer capture/failure、startup、ADR-0450 terminal 与本 ADR resource/rollback
|
||||
组合为可由 rollout v2 loader 独立重放的 manual Primary gate bundle;首次目标实例 manual canary bundle 仍必须在实际启用前产生。
|
||||
固定物理 edge、真实 flash 写放大和断电演练必须作为独立现场证据,不能由本 ADR 的 Docker arm64 结果替代。
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
# ADR-0453:Origin-scoped Legacy Shadow 捕获权威与 Primary 门禁
|
||||
|
||||
- 状态:Accepted
|
||||
- 日期:2026-08-19
|
||||
- 关联 RFC:QL-RFC-0001 D-02、D-360、PR-4、PR-5
|
||||
- 关联 ADR:ADR-0002、ADR-0449、ADR-0450、ADR-0451
|
||||
- Amends:ADR-0002 的 Shadow→Primary 门禁、ADR-0451 的 Legacy→Shadow capture 缺口
|
||||
|
||||
## 上下文
|
||||
|
||||
ADR-0450 能证明已存在的 legacy-owned Shadow Run 与 Legacy 终态一致,但它明确不测量没有 Shadow Run 的 Legacy execution。ADR-0451 又证明
|
||||
资源预算和 enabled→off 回滚,却仍不能把“看到的 Shadow 都正确”推导成“每个 Legacy admission 都被捕获”。旧
|
||||
`shadowBridgeFailureSnapshot()` 只有进程累计失败 key,没有 admission 分母、pending 守恒、测量窗口或可供 rollout loader 重放的权威文件。
|
||||
|
||||
Primary manifest v1 还只要求维护者填写五个 `"passed"`。即使审批和文件摘要有效,运行时也无法重算这些字符串背后的 capture、terminal agreement、
|
||||
startup convergence 与 rollback evidence;把字符串替换为一份只声明 `eligible` 的 receipt 同样不构成门禁。
|
||||
|
||||
## 决策
|
||||
|
||||
1. 已配置 origin 进入默认 Legacy Shadow bridge 后、构造 fact 前,必须取得一次 process-local admission token。token 只能结算为
|
||||
`captured | failed | pending`;`captured + failed + pending = admitted`,failure 进一步固定为 `fact | observer | initialization | accept` 四类并守恒。
|
||||
Legacy spawn、返回值和失败开放语义不变;测试 override 不构成生产 capture authority。
|
||||
2. `LegacyShadowRunObserver` 暴露只读异步 `captureSettled()`:只有真实 `LegacyShadowRunWriter.accept()` 成功才结算 captured。初始化失败、fact 构造失败、
|
||||
observer begin 失败或 accept 失败分别结算到固定失败类;后续 spawned/running/terminal 写入仍由 ADR-0450 终态审计裁决,不能用 accept 成功替代终态一致。
|
||||
3. snapshot schema 为 `qinglong/legacy-shadow-capture-snapshot@v1`,用随机 process epoch、时间和最多七行 origin 固定计数表达,不含 PID、Run、Attempt、Cron、
|
||||
task、command、path、用户或错误消息。window report schema 为 `qinglong/legacy-shadow-capture-report@v1`;起始 snapshot 必须零 pending,同 epoch 前后差分、
|
||||
origin exact coverage 和计数单调必须成立。
|
||||
4. HTTP worker 在 Legacy normalization 和 ADR-0449 startup reconciliation 之后、Primary bootstrap/listen 之前装配一次性 exporter。只有显式设置
|
||||
`QL3_SHADOW_CAPTURE_EVIDENCE_FILE=<basename>.json` 才开启;文件固定写入既有 config root,basename 禁止路径、`.` 前缀和 `..`。exporter 无 timer、watcher、
|
||||
listener、重试队列或数据库连接,只在干净 shutdown 写一次 `0600`、`wx` no-replace JSON;失败只形成低敏审计,不改变 Legacy shutdown。
|
||||
5. capture evidence schema 为 `qinglong/legacy-shadow-capture-evidence@v1`,同时嵌入同进程启动时的 ADR-0449 report。只有 startup `converged`、Profile 与
|
||||
origin 顺序精确一致、capture assessment 为 `captured` 才 qualified;crash、非干净退出、partial/no-replace 写失败、empty、pending 或任一失败都不能产生
|
||||
Primary eligibility。
|
||||
6. `gate:legacy-shadow-primary:ql3` 组合三份低敏输入:capture/startup evidence、ADR-0450 closed terminal report、ADR-0451 compiled-backend full rollback/resource
|
||||
report。当前只允许 `manual`:edge 必须精确 8 个 admission;standalone 为 32–128 个。terminal window 必须与 capture window 逐值相等,scanned/matched 必须
|
||||
等于 captured,closed、evidence complete、无 remaining,terminal agreement 与 fully comparable 都必须为 1000/1000。资源报告必须同 Profile、full、
|
||||
compiled backend、qualified,并证明 Legacy continued、Shadow stopped 与 SQLite integrity `ok`。
|
||||
7. Primary gate bundle schema 为 `qinglong/legacy-shadow-primary-gate@v1`。它嵌入三份 source report、各自 canonical JSON SHA-256、固定计数、window、结论与固定
|
||||
violation code;不嵌入原文件路径。CLI 用 `O_NOFOLLOW`、1 MiB 上限读取输入,并以 `0600`、no-replace 写 bundle;ineligible 时不写输出。
|
||||
8. Rollout manifest 升为 schema v2。enabled manifest 必须增加 `primaryGate` reference,只允许 `manual`、同 config 目录 basename 和 64-hex bundle digest。
|
||||
loader 以 no-follow、64 KiB 上限读取 bundle,验证 manifest digest,重新计算 embedded source canonical digests,并从 source reports 重新执行完整 Primary gate;
|
||||
它不信任 CLI 写入的 `assessment`。bundle 必须 eligible、生成时间不晚于审批时间且 Profile 与实际 Local deployment 相同,之后才可惰性加载 Primary stack。
|
||||
9. v1 enabled manifest 失败关闭,不自动补写或猜测 gate。disabled/missing/rejected 仍保持零 Primary stack、router、timer 和连接。`defaultMode=off`、manual-only、
|
||||
最长 30 天审批、rollback plan 和既有 durable cancellation/atomic projection gates 保留。
|
||||
|
||||
## 被拒绝的替代方案
|
||||
|
||||
### 给 RunningInstances 增加 origin 后直接当分母
|
||||
|
||||
拒绝。2.x 多条 Node/Shell 路径只在 spawn/callback 后写 RunningInstances,缺失行本身不可见,无法证明 admission capture;为兼容观测改成数据库
|
||||
fail-closed 还会改变 Legacy 可用性。
|
||||
|
||||
### 每次 Legacy execution 同步写一条新 admission ledger
|
||||
|
||||
拒绝作为本阶段方案。它会让 Shadow 数据库写参与 Legacy spawn 前置路径,并在低配 flash 上形成第二份逐执行持久化权威。若未来需要跨 crash 的在线连续窗口,必须以
|
||||
独立 migration、retention、写放大和故障语义重新评审,不能暗中加入兼容桥。
|
||||
|
||||
### 只在日志里输出累计 counter
|
||||
|
||||
拒绝。日志片段没有同 epoch 起止、pending baseline、startup report binding、no-replace 文件或 loader 重放;丢日志时也不能 fail-closed。
|
||||
|
||||
### Loader 只验证 `eligible` receipt 的摘要
|
||||
|
||||
拒绝。摘要只能证明文件没变,不能证明内容真实执行 gate。v2 bundle 必须携带低敏 source reports,loader 必须独立重算 digest 和结论。
|
||||
|
||||
## 资源、安全与部署影响
|
||||
|
||||
- 每个已启用 Legacy admission 增加一个常数 token 和四个固定 counter 更新;最多七行 origin,没有按执行身份保存集合,不增加 timer、watcher、listener、线程、连接或
|
||||
schema。未配置 Shadow origins 时仍在 fact factory、observer/Repository import 和 capture authority admission 前返回。
|
||||
- 正常运行不写 capture 文件;只有显式证据 canary 的干净 shutdown 写一个有界文件。edge/standalone runtime 不需要 Prometheus、OTel、外部数据库、对象存储或
|
||||
Cluster 组件。
|
||||
- bundle 是本机 config-root trust domain 内的 rollout evidence,不是签名供应链 attestation。拥有 config root 写权限的 operator 仍是本机信任根;公开分发或跨主机
|
||||
delegation 需另加签名 ceremony。
|
||||
- 本 Gate 只开放 manual eligibility 的判定能力,不自动写 manifest、不启用 Primary、不接管 scheduled/system/boot/gRPC origin,也不证明物理 flash、断电或生产任务内容。
|
||||
|
||||
## 验证
|
||||
|
||||
- 纯 authority 覆盖成功、四类失败、pending、跨 epoch、非零 pending baseline、origin coverage 和脱敏守恒。
|
||||
- exporter 覆盖 armed→exported、clean shutdown、`0600`、no-replace、重复 close、缺失 startup、未配置和失败开放。
|
||||
- gate/CLI 覆盖 exact edge cohort、样本不足、terminal 漂移、audit-only rollback、symlink、no-replace、embedded source 篡改和 canonical digest 重算。
|
||||
- rollout v2 覆盖 missing/tampered/ineligible bundle、审批时间、Profile mismatch、unknown field/path traversal 和 disabled lazy path。
|
||||
- 真实 compiled backend 的 `ScheduleService.runTask` enabled child 已通过默认 observer/Repository 产生一个 `system` capture:admitted/captured 为 1/1,failed/pending 为
|
||||
0/0;它只证明 bridge 真实结算链,不冒充 manual Primary 的 8/32 条正式 canary。
|
||||
- 阶段门已从 clean package artifacts 重跑:D-360 聚焦测试 `48/48`、Legacy/Shadow 串行扩展 `117/117`、资源/回滚专项 `4/4`、`build:back`、
|
||||
完整 backend `1,469 pass / 0 fail / 2 conditional skip`、18-package clean build/test、四项可执行架构审计与 `14/14` Local Profile artifact audit
|
||||
全部通过。产物字节保持 D-358 基线:base `2,589,998 / 2,590,076`、adopted `2,809,293 / 2,809,416`、application
|
||||
`3,632,877 / 3,632,997`、application-api `3,800,430 / 3,800,574`、AI `3,069,251 / 3,069,341`、application+AI
|
||||
`4,493,151 / 4,493,283`、MCP `7,315,930 / 7,316,038`。
|
||||
- Linux arm64 Docker 资源门再次通过:router stress 保持 `128 MiB / 0.5 CPU / 0 swap / 64 PID`,cgroup peak `95,113,216` bytes;Edge release
|
||||
保持 `256 MiB / 1 CPU / 0 swap / 128 PID`,13 个 workload 全部通过,cgroup peak `144,740,352` bytes,`memory.events` 的
|
||||
`max/oom/oom_kill` 增量均为 0。Edge full rollback 中默认 `system` bridge 的真实 capture 为 `1/1`,terminal audit p95 `5.236 ms`、RSS delta
|
||||
`2,621,440` bytes、数据库存储前后稳定。Docker arm64 仍不是物理路由、flash wear 或断电证据。
|
||||
- D-360 未修改 PostgreSQL schema、migration、依赖树或 Kubernetes 拓扑,因此不重跑 PostgreSQL HA;相邻 D-359 的 PostgreSQL HA `142/142` 与
|
||||
timeline `1→2` 只作为未被本阶段触碰的既有证据,不冒充本阶段新结果。
|
||||
|
||||
## 后续
|
||||
|
||||
正式启用 manual Primary 前,维护者必须在目标 edge/standalone 实例完成一次真实、干净关闭的 manual canary,等待 settling 后运行 terminal audit,组合与同版本
|
||||
resource report 生成 bundle,再由 v2 loader 重放。固定物理路由、flash 写放大、断电、非干净退出和 config-root 签名/备份仍是独立发布证据;其他 origin 必须分别建立
|
||||
自己的 admission authority、样本预算和 rollback gate,不能复用 manual receipt。
|
||||
@@ -456,6 +456,7 @@
|
||||
| [ADR-0450](./ADR-0450-closed-window-legacy-shadow-terminal-difference-audit.md) | 闭合窗口的 Legacy Shadow 终态差异审计 | Accepted |
|
||||
| [ADR-0451](./ADR-0451-profile-bounded-legacy-shadow-resource-and-off-rollback-evidence.md) | 按 Profile 有界的 Legacy Shadow 资源与关闭回滚证据 | Accepted |
|
||||
| [ADR-0452](./ADR-0452-atomic-flattened-backend-build-publication.md) | 原子且扁平兼容的 Backend 构建发布 | Accepted |
|
||||
| [ADR-0453](./ADR-0453-origin-scoped-legacy-shadow-capture-authority-and-primary-gate.md) | Origin-scoped Legacy Shadow 捕获权威与 Primary 门禁 | Accepted(首次真实目标实例 manual canary 待执行) |
|
||||
|
||||
## 规则
|
||||
|
||||
|
||||
Reference in New Issue
Block a user