mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-22 19:29:13 +08:00
feat(ql3): audit legacy shadow terminal windows
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。该 startup snapshot 仍不能替代跨测量窗口的历史终态对账与正式 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 的闭合窗口终态审计;但 2.x RunningInstance 缺少可信 origin,因此它只证明已写 Shadow Run 到 Legacy evidence 的一致性,不能单独证明 Legacy→Shadow 捕获率或替代正式 Primary gate。
|
||||
|
||||
### 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,但尚未完成跨窗口终态差异查询、具体 exporter、资源/回滚演练和正式 Primary gate。后续能力不得让 edge 增加常驻 watcher 或无界内存队列。
|
||||
这仍不是完整的 Shadow→Primary 门禁:ADR-0448 已提供启动后有界批量扫描、终态证据补齐、lost/abandoned 收敛和两事务 response-loss 修复;ADR-0449 已增加 startup 差异报表、固定低基数 metric batch 与可注入单次 collector;ADR-0450 已完成不伪造反向捕获率的闭合窗口 Shadow→Legacy 终态差异查询。具体 exporter、Legacy→Shadow capture authority、资源/回滚演练和正式 Primary gate 尚未完成。后续能力不得让 edge 增加常驻 watcher 或无界内存队列。
|
||||
|
||||
### 9.3 Shadow 写失败
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
# ADR-0450:闭合窗口的 Legacy Shadow 终态差异审计
|
||||
|
||||
- 状态:Accepted
|
||||
- 日期:2026-08-18
|
||||
- 关联 RFC:QL-RFC-0001 D-02、D-358、PR-4
|
||||
- 关联 ADR:ADR-0002、ADR-0448、ADR-0449
|
||||
- Amends:ADR-0449 的跨测量窗口待办
|
||||
|
||||
## 上下文
|
||||
|
||||
ADR-0448/0449 只证明一次启动时 active Shadow Run 的恢复结果,不能回答一个明确时间段内已经写入的 Shadow Run 是否与 Legacy 执行终态一致。
|
||||
直接用 startup scanned 计算比例会把未知尾页和未稳定执行混入分母;把全部 `RunningInstances` 当成 Shadow 应写集合也不成立,因为 QingLong 2.x
|
||||
表没有可信的 execution origin,manual、system crond 与其他 Legacy 路径可能复用同一 Cron。
|
||||
|
||||
部署跨度还要求同一能力既能在低性能路由设备运行,也能在 standalone 节点处理较大窗口。审计不能增加启动查询、常驻 timer、第二数据库 authority、
|
||||
无界数组或高基数指标,更不能为了“补齐”历史数据而改写 Run/Attempt/RunningInstance。
|
||||
|
||||
## 决策
|
||||
|
||||
1. 新增显式、只读、一次性的 `audit:legacy-shadow-terminal:ql3` 运维入口。调用方必须给出至少一个已支持 Shadow origin 以及
|
||||
`[windowStartMs, windowEndMs)`;窗口 cohort 以 `legacy-owned Shadow Run.created_at_ms` 为准,不自动选择“最近一段时间”。
|
||||
2. 窗口只有在 `windowEndMs <= observedAtMs - minimumSettlingAgeMs` 时闭合,默认 settling age 为五分钟。窗口未闭合、候选页未扫完或
|
||||
Legacy evidence 达到硬上限时,不输出任何比例。
|
||||
3. Source 使用 `(created_at_ms, run_id)` 稳定 keyset,复用现有 `Runs(project_id, created_at_ms)` 索引;Run 与 latest Attempt 在同一有界查询中读取。
|
||||
每页再执行一次有界 RunningInstance evidence 查询,不逐 candidate 发出 N+1 查询。单页候选硬上限 64、Legacy evidence 硬上限 512。
|
||||
4. Profile 默认预算保持与 startup recovery 一致:edge `8 × 1 page`,standalone `32 × 4 pages`。查询不安装 timer、watcher、线程、进程、连接池
|
||||
常驻生命周期或后台续扫;预算耗尽返回 `incomplete`,操作者缩小窗口后重试。
|
||||
5. 关联优先级固定为 direct Attempt/Run reference,其次同 Cron 下的 opaque log artifact ID、PID,最后才允许唯一且在容差内的 started time。
|
||||
多个候选或 evidence 截断一律归入 ambiguous,不用“最近一条”猜测。原始 log path 只在 adapter 内哈希,不进入 application/report。
|
||||
6. 每个 Shadow candidate 必须且只能归入八类之一:`matched`、`shadow_not_terminal`、`shadow_attempt_missing`、
|
||||
`shadow_attempt_ambiguous`、`legacy_evidence_missing`、`legacy_evidence_ambiguous`、`status_mismatch`、`field_mismatch`。
|
||||
aggregate 与按 origin matrix 都必须守恒。
|
||||
7. status、exit code、started time、finished time 与 log artifact 使用固定 dimension counters 记录 compared/matched/mismatched/unavailable。
|
||||
时间默认允许两秒精度差,硬上限一分钟;`terminalAgreementPermille` 与 `fullyComparablePermille` 只在窗口闭合、候选与 evidence 都完整且分母非零时出现。
|
||||
8. 报告 schema 为 `qinglong/legacy-shadow-terminal-difference-report@v1`。报告只包含 Profile、窗口、预算、固定计数、最多七条 origin matrix 和
|
||||
`matched/empty/differences_found/window_open/incomplete` assessment;不输出 Project/Run/Attempt/Cron/PID/log/task/user/error identity。
|
||||
9. 报告明确声明 `direction=shadow_to_legacy` 和 `legacyWithoutShadow=not_measured`。当前数据模型无法可靠证明“存在 Legacy 执行但 Shadow Run 未写入”,
|
||||
因而本报告不能单独作为 Primary gate;D-360 必须组合 observer failure/capture evidence,或先引入可信 origin-scoped admission ledger。
|
||||
10. 审计不写数据库、不修复差异、不启动 Executor、不改变 Legacy 返回值。`--fail-on-difference` 只把非 `matched` assessment 映射为进程退出码 1,
|
||||
供人工 rollout/CI gate 使用。
|
||||
|
||||
## 资源与部署影响
|
||||
|
||||
- 不新增 package、生产依赖、schema、migration、表、索引、数据库 authority、HTTP/gRPC 路由、timer、watcher、worker、容器或 Kubernetes 对象。
|
||||
- edge 默认最多读取 8 个 Shadow candidate 与 64 条 Legacy evidence;standalone 默认最多 128 个 candidate 与每页 256 条 evidence。
|
||||
- CLI 数据库连接固定只读、单连接池;报告为固定字段 aggregate,不保留 candidate identity,也不建立进程内累计 registry。
|
||||
- `Runs(project_id, created_at_ms)` 负责 cohort keyset;RunningInstance 查询每页一次且结果有硬上限。若未来固定设备证明表扫描 CPU 不可接受,应通过新 migration
|
||||
增加 `(cron_id, started_at, id)` 索引并单独评审升级写放大,而不是在本 ADR 中静默修改已发布 migration checksum。
|
||||
|
||||
## 被拒绝的替代方案
|
||||
|
||||
### 双向扫描所有 RunningInstances 并计算 Shadow 捕获率
|
||||
|
||||
拒绝。2.x `RunningInstances` 没有可信 execution origin,无法知道某条记录是否属于已开启 Shadow 的入口;把它们都放进分母会制造假阴性。
|
||||
|
||||
### 在每次 HTTP startup 自动审计历史窗口
|
||||
|
||||
拒绝。它会重复 D-356 的启动查询、延迟路由设备监听,并需要隐式选择时间窗口。历史证据必须由操作者显式触发。
|
||||
|
||||
### 为每个 Shadow candidate 单独查 RunningInstances
|
||||
|
||||
拒绝。即使 candidate 数有上限,N+1 仍会让低性能 SQLite 设备承担不必要的查询调度和重复表扫描。
|
||||
|
||||
### 只输出差异明细 ID 方便排障
|
||||
|
||||
拒绝。运维日志会泄露高基数任务身份;需要明细时应新增受认证、Project-scoped 的诊断产品面,而不是扩大默认 CLI 报告。
|
||||
|
||||
## 验证
|
||||
|
||||
- 真实 SQLite 覆盖完全一致、status/exit field 差异、missing/ambiguous evidence、active Shadow、窗口未闭合、edge 页预算耗尽、evidence overflow、
|
||||
双 origin 守恒、空分母和只读 CLI 脱敏输出。
|
||||
- 真实 SQLite/CLI 聚焦测试 `14/14`、Legacy/Shadow 串行扩展 `91/91`、`build:back`、完整 backend
|
||||
`1,455 pass / 0 fail / 2 conditional skip`、18-package clean build/test、14/14 static audit 与 14/14 artifact audit 全部通过。
|
||||
- edge/standalone 的 base、adopted、application、application-api、AI、application+AI、MCP 产物分别为
|
||||
`2,589,998 / 2,590,076`、`2,809,293 / 2,809,416`、`3,632,877 / 3,632,997`、
|
||||
`3,800,430 / 3,800,574`、`3,069,251 / 3,069,341`、`4,493,151 / 4,493,283`、
|
||||
`7,315,930 / 7,316,038` bytes,与 D-357 完全一致。
|
||||
- 本切片不修改 PostgreSQL、容器或 Kubernetes 部署面,因此物理 PostgreSQL HA/K3s 门不作为本切片的新证据;D-359 仍负责 edge/standalone 资源压力与
|
||||
Shadow-off 回滚演练。
|
||||
@@ -453,6 +453,7 @@
|
||||
| [ADR-0447](./ADR-0447-boot-shadow-and-non-origin-boundaries.md) | Boot Shadow 准入与 once/gRPC 非 Origin 边界 | Accepted |
|
||||
| [ADR-0448](./ADR-0448-bounded-legacy-shadow-startup-reconciliation.md) | 有界 Legacy Shadow 启动恢复 | Accepted |
|
||||
| [ADR-0449](./ADR-0449-versioned-legacy-shadow-startup-difference-report-and-metrics.md) | 版本化 Legacy Shadow 启动差异报告与指标批次 | Accepted |
|
||||
| [ADR-0450](./ADR-0450-closed-window-legacy-shadow-terminal-difference-audit.md) | 闭合窗口的 Legacy Shadow 终态差异审计 | Accepted |
|
||||
|
||||
## 规则
|
||||
|
||||
|
||||
Reference in New Issue
Block a user