mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
feat(ql3): prove shadow resource rollback
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 的闭合窗口终态审计;但 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 回滚。但 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;ADR-0450 已完成不伪造反向捕获率的闭合窗口 Shadow→Legacy 终态差异查询。具体 exporter、Legacy→Shadow capture authority、资源/回滚演练和正式 Primary gate 尚未完成。后续能力不得让 edge 增加常驻 watcher 或无界内存队列。
|
||||
这仍不是完整的 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 或无界内存队列。
|
||||
|
||||
### 9.3 Shadow 写失败
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# ADR-0451:按 Profile 有界的 Legacy Shadow 资源与关闭回滚证据
|
||||
|
||||
- 状态:Accepted
|
||||
- 日期:2026-08-19
|
||||
- 关联 RFC:QL-RFC-0001 D-02、D-359、PR-4
|
||||
- 关联 ADR:ADR-0002、ADR-0088、ADR-0450
|
||||
- Amends:ADR-0450 的资源压力与 Shadow-off 回滚待办
|
||||
|
||||
## 上下文
|
||||
|
||||
ADR-0450 已冻结闭合窗口的 Shadow→Legacy 终态审计语义,但只证明查询结果,不证明它能在 128 MiB 路由档运行,也没有证明进程重启后把
|
||||
`QL3_SHADOW_ORIGINS` 从 enabled 改为 off 会立即停止新 Shadow 写入而继续执行 Legacy。单元测试或主机 RSS 不能替代受限 Linux cgroup;反过来,
|
||||
在 128 MiB 门中同时驻留 Node 测试父进程和预期被 SIGKILL 的子进程,也不是路由设备的单进程产品模型。
|
||||
|
||||
资源门此前还要求 `/workspace` 必须是独立只读 mount。只读容器根已经让该路径继承只读语义;额外复制约 1.5 GiB 工作区到匿名 volume 会把私有页缓存
|
||||
计入 128 MiB cgroup,制造与产品 RSS 无关的 `memory.events max`。门禁必须验证路径实际生效的最具体 mount,并拒绝 `/workspace/**` 的任何可写覆盖,
|
||||
而不是要求一种特定 mount 拓扑。
|
||||
|
||||
## 决策
|
||||
|
||||
1. 新增一次性证据入口 `benchmark:legacy-shadow`,报告 schema 固定为
|
||||
`qinglong/legacy-shadow-resource-rollback-evidence@v1`。报告只包含 Profile、预算、固定资源计数、回滚布尔结论和限制,不输出数据库路径、命令、Run、Attempt、
|
||||
Cron、PID、log 或 task identity。
|
||||
2. 审计 fixture 使用真实 Sequelize + SQLite、真实 migration、真实 Legacy Shadow writer 和 ADR-0450 auditor。edge 固定 8 个 candidate、`8 × 1 page`;
|
||||
standalone 固定 128 个 candidate、`32 × 4 pages`。每页必须精确执行一条 candidate 查询和一条 evidence 查询;8 个样本分别固定为 16 和 64 条查询。
|
||||
3. 审计连接为单连接、SQLite read-only。运行前后同时比较 database、WAL、SHM 与 journal 的 logical bytes、allocated bytes 和 file count;任一变化均失败。
|
||||
4. `full` 模式必须启动三个独立进程:audit、Shadow-enabled Legacy execution、重启后的 Shadow-off Legacy execution。enabled 进程必须执行真实
|
||||
`ScheduleService.runTask` 子进程、Legacy exit 0 且恰好新增一个 terminal Shadow Run;off 进程仍须 Legacy exit 0,但 configured origins 为空、fact factory
|
||||
调用为零、默认 Shadow observer/Repository 未加载且 Run 增量为零。
|
||||
5. Legacy `TaskLimit` 构造器的异步数据库初始化必须在调度和 teardown 前通过同一单例显式等待;证据进程不得用 sleep、吞掉 unhandled rejection 或提前关闭
|
||||
Sequelize 来伪造成功。
|
||||
6. `router-stress-ci` 保持 128 MiB、0 swap、0.5 CPU、64 PID、非 root、只读根、`NoNewPrivs` 和 seccomp,只运行 edge audit-only。该档位保留真实 Edge
|
||||
executor、产品 Workflow、SQLite lock 和失败升级恢复,但不运行需要同时驻留测试父/子 Node 的 crash matrix。
|
||||
7. `edge-release-ci` 保持 256 MiB、0 swap、1 CPU、128 PID,并运行 edge full rollback、standalone audit-only,以及 Edge+Standalone 的完整 Workflow/Prompt
|
||||
crash matrix。把双进程 crash harness 放到发布门不减少覆盖,也不把测试框架开销冒充路由产品最低内存。
|
||||
8. mount 验证按目标路径选择最具体 mount。`/workspace` 可继承只读 `/`,但其任一可写 descendant mount 都使门禁失败;`/tmp` 仍必须是独立、可写且有容量上限的
|
||||
tmpfs。门禁不得为满足断言而复制整个工作区。
|
||||
9. 资源报告继续对 `memory.events max/oom/oom_kill/oom_group_kill` 的任一增量失败,不以“没有 OOM”接受内存触顶;也不放宽既有 latency、RSS、写放大或
|
||||
SQLite integrity contract。
|
||||
10. 本证据只证明 CI 容器内的有界行为,不证明物理路由、flash wear、断电存活、生产任务内容、Legacy→Shadow capture rate、Primary eligibility、
|
||||
PostgreSQL 或 Cluster runtime。
|
||||
|
||||
## 被拒绝的替代方案
|
||||
|
||||
### 把路由内存上限提高到 192/256 MiB
|
||||
|
||||
拒绝。失败来自测试拓扑和 workspace volume 页缓存,不是产品 Edge workload 超出预算;扩大内存会掩盖错误建模。
|
||||
|
||||
### 增大 crash child 的 30 秒 timeout
|
||||
|
||||
拒绝。128 MiB 下父/子双 Node 的回收抖动不是业务时延。完整 crash matrix 已在 256 MiB 发布门保留,路由门不应靠等待更久制造假稳定。
|
||||
|
||||
### Shadow-off 只调用配置解析函数
|
||||
|
||||
拒绝。回滚证据必须经过进程重启、真实 Legacy child 和数据库计数,证明 off 路径在执行发生时不构造 fact、不加载默认写入组件。
|
||||
|
||||
## 验证
|
||||
|
||||
- 主机聚焦门 `23/23`;edge full 与 standalone audit-only 都使用 compiled backend 并通过数据库完整性检查。
|
||||
- Linux arm64 router gate:128 MiB/0.5 CPU/0 swap/64 PID,cgroup peak `80,416,768` bytes;所有 `memory.events` 增量为 0。edge audit 8 个样本、16/16 查询、
|
||||
p95 `3.914 ms`、RSS 增量 `131,072` bytes,SQLite storage 前后相同。
|
||||
- Linux arm64 edge release gate:256 MiB/1 CPU/0 swap/128 PID,cgroup peak `139,079,680` bytes;所有 `memory.events` 增量为 0。edge full audit p95
|
||||
`32.056 ms`、16/16 查询、RSS 增量 `3,407,872` bytes;enabled/off Legacy 均 exit 0,Run 增量分别为 1/0,进程峰值 RSS 分别为
|
||||
`94,224,384 / 92,577,792` bytes。standalone audit 为 32 pages、64/64 查询、p95 `19.265 ms`、RSS 增量 `1,572,864` bytes,SQLite storage
|
||||
前后相同。
|
||||
- 同一发布门完整通过 Workflow admission/control、Prompt model/outer transaction 等 Edge+Standalone crash matrix;Prompt live execution 与 exact replay
|
||||
固定发生 2 次 key resolution、1 次 key load,门禁拒绝计数漂移。
|
||||
- 完整 `test:back` 与 18-package clean build/test 均退出 0;五个 package/deployment/image/vulnerability 静态契约文件为 `126/126`,Edge import、
|
||||
Cluster dependency、package boundary 与 Cluster deployment 四个可执行审计均为 compatible 且零 finding。14 个 Local Profile artifact 全部通过预算;
|
||||
Edge/Standalone 字节依次为: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`。
|
||||
|
||||
## 后续
|
||||
|
||||
D-360 仍须建立可信的 origin-scoped Legacy→Shadow capture authority,组合 observer failure/capture evidence 与本 ADR/ADR-0450 的结果,再定义正式 Primary gate。
|
||||
固定物理 edge、真实 flash 写放大和断电演练必须作为独立现场证据,不能由本 ADR 的 Docker arm64 结果替代。
|
||||
@@ -0,0 +1,51 @@
|
||||
# ADR-0452:原子且扁平兼容的 Backend 构建发布
|
||||
|
||||
- 状态:Accepted
|
||||
- 日期:2026-08-19
|
||||
- 关联 RFC:QL-RFC-0001 D-359
|
||||
- 关联 ADR:ADR-0042、ADR-0106、ADR-0451
|
||||
|
||||
## 上下文
|
||||
|
||||
Backend TypeScript 开始引用 QL3 workspace source 后,TypeScript 的 common source root 扩展到仓库根。一次真正清空输出目录的构建会生成
|
||||
`static/build/back/app.js` 与 `static/build/packages/**`,但 2.x 生产入口和现有镜像仍要求 `static/build/app.js`、`token.js`、`runtime/**` 等稳定路径。
|
||||
开发机长期残留的旧 `static/build/*` 会掩盖该错位,使增量构建和测试通过,而干净镜像不可启动。
|
||||
|
||||
直接把所有生产入口改到 `static/build/back/**` 会扩大 2.x 部署、CLI、Docker 与 Shell 兼容面;把 workspace package 编译副本发布进 backend 目录又会形成第二套
|
||||
package authority。构建必须只发布 backend subtree,同时保持既有路径和可追踪 source map。
|
||||
|
||||
## 决策
|
||||
|
||||
1. `build:back` 唯一进入 `scripts/ql3-build-back.cjs`,不再直接把 `tsc` 输出到公开的 `static/build`。
|
||||
2. 每次构建在 `static/.back-build-<pid>-<nonce>/output` 隔离目录执行 `tsc -p back/tsconfig.json --outDir ...`。失败时保留当前公开构建,不允许半成品覆盖。
|
||||
3. 发布前必须验证 staged `back/app.js`、`back/token.js`、`back/runtime/adapters/local-process/localProcessExecutor.js` 等必要输出存在;
|
||||
`output/packages/**` 只作为编译闭包,不进入公开 backend。
|
||||
4. 只把 staged `output/back` 发布为扁平的 `static/build`,因此生产路径继续是 `static/build/app.js`、`runtime/**`,不要求修改 2.x 入口。
|
||||
5. 发布前重写 `.js.map` 的 relative sources,使其从最终扁平位置仍能解析到真实 `back/**` source;不得删除 map 或留下指向临时 staging 的路径。
|
||||
6. 发布采用同一父目录内 rename:现有 build 先改名为唯一 backup,staged backend 再 rename 到目标;只有新目录成功可见后才删除 backup。发布失败时恢复旧目录并清理精确
|
||||
staging/backup,不使用 shell、glob 或仓库级删除。
|
||||
7. 构建结束后 `static/build/back` 与 `static/build/packages` 必须不存在。测试和镜像门必须从干净输出执行,禁止依赖历史 artifact。
|
||||
|
||||
## 被拒绝的替代方案
|
||||
|
||||
### 修改所有生产入口指向 `static/build/back`
|
||||
|
||||
拒绝。它把 TypeScript 内部 common-root 变化泄露成部署契约变化,并扩大 2.x 回滚风险。
|
||||
|
||||
### 构建前清空 `static/build` 后直接运行 tsc
|
||||
|
||||
拒绝。它仍发布错误目录,并在编译失败时破坏最后一个可运行构建。
|
||||
|
||||
### 同时发布 `output/back` 与 `output/packages`
|
||||
|
||||
拒绝。QL3 package 已有独立 dist/artifact gate,backend 不应携带另一份 workspace package 实现。
|
||||
|
||||
## 验证
|
||||
|
||||
- 主机和干净 Linux arm64 镜像中的 `pnpm build:back` 均通过;最终目录只保留原有 root layout,不存在 `static/build/back` 或
|
||||
`static/build/packages`。
|
||||
- source map 从最终 `static/build/runtime/**` 位置可解析回仓库 `back/runtime/**`,不引用临时 staging。
|
||||
- Edge benchmark、D359 compiled-backend 资源/回滚门和完整 backend 回归均只读取新的干净发布结果。
|
||||
- 完整 backend 回归与 18-package clean build/test 均退出 0;五个静态契约文件 `126/126`,四个可执行架构审计和 14 个 Local Profile artifact
|
||||
预算全部通过,证明扁平 backend 发布没有改变 package closure 或 Profile 制品基线。
|
||||
- 本 ADR 不改变 package graph、生产依赖、schema、migration、数据库或部署 authority。
|
||||
@@ -454,6 +454,8 @@
|
||||
| [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 |
|
||||
| [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 |
|
||||
|
||||
## 规则
|
||||
|
||||
|
||||
Reference in New Issue
Block a user