feat: publish Dever core with project scaffolding and versioned AI skills

This commit is contained in:
Antigravity committed 2026-10-04 13:37:30 +00:00
1 parent 70fa73cdc2
commit ac458ffa7f
960 files changed
+221319 -1163

No files matched your search

@@ -0,0 +1,3 @@
{"file":".trellis/spec/backend/error-handling.md","reason":"检查错误、OOM、计数和进程退出都显式传播"}
{"file":".trellis/spec/backend/quality-guidelines.md","reason":"核对 CPU 隔离、测量矩阵、最小测试和结果边界"}
{"file":".trellis/tasks/09-13-http2-ceiling-soak/research/client-bottleneck.md","reason":"检查实现没有引入重复负载器或错误分位数聚合"}
@@ -0,0 +1,70 @@
# 设计
## 1. 最小改动边界
本阶段只扩展 `test/performance` 的负载进程配置和测量文档。现有 Rust `network_bench` 已具备多线程 runtime、固定 HTTP/2 连接拓扑、速率调度、完整响应校验和延迟直方图,因此不修改 Rust 负载器,更不修改生产运行时。
多进程客户端会产生多组独立直方图。只合并 p99 会得到错误分位数,输出全部 4096 个桶再聚合又会扩大协议和实现范围。一个多线程进程已经能把请求 worker 分布到多个 CPU,同时保留单一调度和精确的进程内直方图,因此采用该方案。
## 2. CPU 与 worker 合同
`Process` 的亲和性参数从单个 `cpu` 改为可空的 `cpus` 集合,并在 fork 后、exec 前一次性调用:
```text
os.sched_setaffinity(0, cpus)
```
服务端仍把 `--server-cpu` 转为单元素集合。运行器将 `--client-cpu` 直接迁移为 `--client-cpus`,接受无重复的逗号分隔非负整数;新增 `--client-workers`,默认 1。运行前集中校验:
- 所有指定 CPU 必须属于当前进程允许集合;
- 服务 CPU 不得出现在客户端 CPU 集合;
- 正式压测显式使用 `--client-workers 4 --client-cpus 1,2,3,4`。
不强制 worker 数等于 CPU 数,避免把合理的欠订阅/超订阅变成运行器错误;报告必须同时记录两者,使结果可解释。HTTP `load()` 和 `live.load_live()` 都把 `BENCH_WORKERS` 设置为同一个 `args.client_workers`,并把同一个 CPU 集合交给 `Process`。
## 3. 数据流与复用
```text
run.py 参数与集中校验
-> Process(cpus=client_cpus)
-> BENCH_WORKERS=client_workers
-> 现有 network_bench 单进程 Tokio runtime
-> 现有 H2 连接/请求槽、调度、校验、Histogram
-> 现有 load JSON、进程采样、case/report 汇总
```
`Process` 继续只负责子进程生命周期、亲和性和采样;它不解释 server/client 角色。`run.py` 负责参数合同与服务/客户端隔离。`live.py` 只消费已经校验的参数,不新增一套 CPU 解析逻辑。
## 4. 测量阶段
所有正式场景只测 Dever,服务绑定 CPU 0、1 worker、1 CPU quota、swap 0;客户端绑定 CPU 1–4、4 workers,位于服务 cgroup 之外。使用现存 `typed-orm-build-v2` 指纹产物和 16 流配置;先验证其 HTTP/2 二进制、TLS 文件和清单,不重建生产产物。
### 饱和扫描
- 预算:128 MiB
- 路径:`/plain`
- 传输:h2c、TLS+h2
- 拓扑:16x16(256 请求槽)
- offered rate:30000、45000、60000、90000 req/s
- 每 case:1 秒预热、5 秒测量、2 个 repeat
若 90000 仍未出现平台,则只报告“扫描上界不足”,不继续无界提高负载。观测平台取成功 QPS 不再随 offered rate 近似线性增长的区间,不把容量丢弃计为服务错误。
### 60 秒稳态
从扫描得到的 h2c/TLS+h2 较低平台值向下取整到不高于 80% 的明确整数 rate,确保两种传输使用相同负载。128 MiB 和 64 MiB 各运行 h2c/TLS+h2 一个 60 秒 case。99% 成功率门槛只用于证明选定 rate 可持续,不用于定义服务极限。
### 连接恢复耐久
128 MiB 下,h2c/TLS+h2 各在同一服务进程运行 100 轮;每轮 16 条物理连接、每连接 16 流、0.1 秒、1000 req/s,随后使用既有 0.3 秒断开观测。每轮校验握手、请求错误和 FD 回落,整组检查 cgroup OOM 与 RSS 序列。
## 5. 风险与解释
- 多线程负载器仍有单一速率调度协程。如果扫描中客户端 CPU 未扩展、dispatch expired 显著而服务端未满 1 核,本阶段应如实判定压测器仍受调度器限制;是否实现分片调度另建任务,不能伪称服务端平台。
- 客户端和服务端仍共享同一虚拟机,只是 CPU 集合隔离;缓存、内存带宽和宿主机噪声仍然共享。
- 64 MiB cgroup 的文件页计费受热缓存影响,继续同时报告进程 RSS/PSS 和 cgroup peak,不以任一单值替代另一个。
- 100 轮是分钟级重复回收证据,不是小时级泄漏或生产网络稳定性证明。
## 6. 回退
改动不涉及生产代码。若 CPU 集合支持造成回归,回退 Python 运行器、测试和文档即可;已有构建产物和历史报告不修改,新测量始终写入新输出目录。
@@ -0,0 +1,3 @@
{"file":".trellis/spec/backend/directory-structure.md","reason":"保持 Python runner、进程采样和 Rust 协议负载的职责边界"}
{"file":".trellis/spec/backend/quality-guidelines.md","reason":"遵守性能测量公平性、资源预算、报告和最小验证要求"}
{"file":".trellis/tasks/09-13-http2-ceiling-soak/research/client-bottleneck.md","reason":"复用已有多线程能力并避免不可合并的多进程分位数"}
@@ -0,0 +1,32 @@
# 执行计划
## 1. 启动与上下文
- [x] 用户确认后运行 `task.py start`;启动前不修改基准源码。
- [x] 使用 `trellis-before-dev` 重新加载 backend 规范,核对当前 diff、磁盘、CPU、cgroup 和正式构建产物;`build-http2-final` 已不在工作树,改用参数满足需求的 `typed-orm-build-v2`,仍须校验指纹。
## 2. 客户端并行配置
- [x] 将 `Process(cpu=...)` 收敛为 `Process(cpus=...)`,所有调用者一次性迁移;保持亲和性只作用于自有子进程。
- [x] 在 `run.py` 增加 CPU 集合解析、集中分配校验、`--client-cpus` 和 `--client-workers`,删除旧 `--client-cpu`。
- [x] 让 HTTP/HTTP2 与 live 客户端共同使用相同 worker 数和 CPU 集合;更新 report environment/arguments。
- [x] 清理重复解析与分支,确保进程生命周期、运行器合同和协议负载职责仍分离。
## 3. 定向验证
- [x] 扩展 `test_runner.py`,覆盖 CPU 集合解析、重复/越界/重叠拒绝、子进程实际亲和性和报告配置。
- [x] Python 语法解析与 runner 34/34 通过;HTTP/2 产物指纹校验通过,未运行全量测试。
- [x] `http2-ceiling-smoke-09-18`:h2c/TLS+h2 各 30/30 成功、16/16 握手、FD 差 0、OOM 0,报告确认 4 workers、CPU 1–4、客户端 5 线程。
## 4. 有界正式测量
- [x] `http2-ceiling-scan-09-18`:128 MiB、16x16、30k/45k/60k/90k、h2c/TLS+h2、5 秒、2 repeats 共 16/16 完成,错误/OOM/FD 差为 0。
- [x] 30k 档 h2c/TLS+h2 吞吐约 29.9k/29.8k;45k 以上 h2c 约 34–40k、TLS+h2 约 37–39k,服务端接近 1 核、客户端 1.4–2.0 核,请求槽丢弃主导,调度过期很少。28k 的 60 秒首轮分别只有 98.68%/97.91% 成功;24k 的 10 秒校准 TLS+h2 只有 99.18%。20k 的 10 秒校准分别为 99.96%/99.92%,据此将正式共同稳态输入定为 20,000 req/s(低于较低观测平台的 80%)。
- [x] `http2-ceiling-steady-128m-20k-09-18` 与 `http2-ceiling-steady-64m-20k-09-18`:h2c/TLS+h2 各 60 秒,成功率依次为 99.77%/99.92% 和 99.94%/99.80%,吞吐约 19.95k–19.99k req/s;全部零错误/OOM、FD 差 0。28k 首轮两项不足 99%,保留该报告为探索证据。
- [x] `http2-ceiling-recovery-09-18`:128 MiB 下 h2c/TLS+h2 各 100/100 轮,分别成功 9,944/10,000 请求,余下 56 次/组为调度过期;每轮至少成功 95/98 个,16 次握手、FD 差 0,请求错误/OOM 为 0。首末轮断开后 RSS 为 4,845,568→5,357,568 B / 5,959,680→6,647,808 B,完整逐轮序列保留。
## 5. 收尾
- [x] 更新 `test/performance/README.md` 与 backend 性能规范中的 CLI、测量结果和限制;HTTP/HTTPS 30/30、TCP/WS/SSE 16/16 最小相邻入口回归通过。
- [x] 检查了入口到子进程的 CPU/worker 传递、重复、职责、命名和无关改动;未改生产运行时或覆盖历史报告,空 frontend 模板是单独已归档的 bootstrap 任务。
- [x] `trellis-check`:runner 定向单测 34/34、Python AST、构建清单指纹、扫描/稳态/恢复报告计数与 OOM/FD/握手不变量、空白检查均通过;HTTP/HTTPS 与 TCP/WS/SSE 最小回归通过。未运行全量测试、Cargo build、rustfmt/clippy;未提交 Git。
@@ -0,0 +1,42 @@
# HTTP/2 饱和边界与耐久压测
## 目标
解除现有 HTTP/2 压测客户端的单核限制,在服务端固定 1 CPU、128 MiB/64 MiB、无 swap 的条件下,测量 Dever HTTP/2 小响应的本机饱和边界、60 秒稳态表现和重复连接恢复表现。结果用于判断后续是否存在值得单独优化的生产热路径,不把本机 loopback 数字外推为跨机器或生产环境上限。
## 已确认事实
- `network_bench` 已使用 Tokio 多线程 runtime,并通过 `BENCH_WORKERS` 控制 worker 数;HTTP/2 请求调度、响应校验、计数守恒和延迟直方图已有单一实现。
- `test/performance/run.py:258` 把负载端 `BENCH_WORKERS` 固定为 1,`test/performance/process.py:104` 只允许子进程绑定一个 CPU。此前 30000 req/s 的 Dever 4x16 场景中,服务端和客户端均约占 0.9 核,因此现有数据不能区分两端上限。
- 已构建清单允许 32 条物理连接、每连接 16 流、任务容量 272;16x16 需要 272 个服务任务,正好落在已有容量内,无需重新配置生产运行时。
- Rust 负载结果只有一个进程内的完整直方图。拆成多个客户端进程后,现有 p50/p95/p99 摘要无法无损合并;使用一个多线程负载进程可以保留现有统计合同。
- 当前机器允许 CPU 0–4;正式测量可将服务绑定 CPU 0,将负载端限制到 CPU 1–4。现有构建产物生命周期为 3600 秒,足以完成单个 60 秒场景和 100 轮恢复场景。
## 需求
- 将基准进程的单 CPU 亲和性扩展为明确的 CPU 集合;服务端继续使用单 CPU,客户端可使用多个互不重复且不与服务 CPU 重叠的 CPU。
- 运行器新增明确的客户端 worker 数和客户端 CPU 集合参数,统一用于 HTTP、HTTP/2 和长连接负载;报告记录实际 worker 数和 CPU 集合。
- 仓库内调用者一次性迁移到新的客户端 CPU 集合参数,不保留旧 `--client-cpu` 别名或兼容分支。
- 多线程客户端继续复用一个 `network_bench` 进程、一套请求调度和一组原始直方图;不新增协议实现,不增加多进程结果拼接器。
- 使用现存 `typed-orm-build-v2` 指纹产物(原 `build-http2-final` 已不在工作树,HTTP/2 配置仍为 32 连接、16 流、272 任务),先对 Dever `/plain`、h2c 和 TLS+h2、16x16 拓扑扫描多个 offered rate,区分客户端限制、请求槽限制和服务端饱和。
- 根据扫描结果选择不高于观测平台 80% 的整数 offered rate,分别完成 h2c 和 TLS+h2 的 60 秒稳态测量;128 MiB 与 64 MiB 服务预算均覆盖,服务 CPU 固定为 1 核,swap 为 0。
- 在同一 Dever 服务进程上对 h2c 和 TLS+h2 分别完成 100 轮 16x16 建连、请求、断开,逐轮保留计数、FD 和 RSS 回落数据。
- 所有正式 case 必须保留请求计数、延迟、服务端/客户端 CPU 与内存、cgroup peak/OOM、握手数和断开后 FD 数据;失败时保留已完成结果与日志。
## 验收标准
- [x] 定向测试证明进程可绑定 CPU 集合,CPU 参数拒绝空值、重复值、越界值以及与服务 CPU 重叠的配置。
- [x] 报告中的 `client_workers` 与 `client_cpus` 等于实际配置;负载进程采样可报告超过单核的总 CPU 使用率,且服务端仍只绑定一个 CPU。
- [x] HTTP/1、HTTP/2 和长连接负载共用同一客户端并行配置入口;现有协议调度、响应校验和直方图实现未复制。
- [x] 16x16 饱和扫描覆盖 h2c/TLS+h2 和至少四个递增 rate;全部请求计数守恒、请求错误为 0、握手数等于物理连接数、无 OOM,报告能识别吞吐平台或确认扫描上界仍不足。
- [x] 128 MiB 与 64 MiB 下各完成 h2c/TLS+h2 的 60 秒稳态 case;请求错误和 OOM 为 0,成功率不低于计划请求的 99%,结束后 FD 回到 READY 基线。
- [x] h2c/TLS+h2 各完成 100 轮 16x16 恢复;每轮至少有成功请求、错误为 0、握手数正确、FD 回到 READY 基线,RSS 序列如实记录且不把短时平台误称为无泄漏证明。
- [x] 文档记录命令、机器约束、扫描结果、稳态/恢复结果和限制;明确区分本机观测饱和点、可持续负载与跨机器性能。
- [x] 只运行受影响的 Python 单元测试、最小 loopback smoke、现有产物指纹校验和显式有界压测;不运行全量测试,不接触已有服务,不提交 Git。
## 排除项
- 修改 `crates/dever-runtime`、编译器、语言 API 或 HTTP/2 生产协议路径。
- 多进程客户端、跨进程直方图合并、新压测依赖或第二套结果格式。
- 跨主机、公网、丢包/限速注入、HTTP/3、RFC 8441 或小时级 soak。
- 预设固定 QPS 门槛、与 Go/Fiber 的跨机器数字比较,或根据一次短测直接修改生产热路径。
@@ -0,0 +1,27 @@
# 客户端瓶颈证据
## 现有实现
- `test/dever-tests/examples/network_bench/load.rs` 从 `BENCH_WORKERS` 创建 Tokio multi-thread runtime,范围为 1–64。HTTP/2 的物理连接、请求 worker、速率调度、响应校验和三组 Histogram 均在该进程内完成。
- `test/performance/run.py` 的 `load()` 无条件写入 `BENCH_WORKERS=1`,并通过 `args.client_cpu` 把负载进程绑定到一个 CPU;`live.py` 使用相同单 worker/单 CPU 方式。
- `test/performance/process.py` 的 `Process` 已集中拥有 fork 后亲和性设置,只需把单元素集合推广为调用方提供的集合,不需要新增进程封装。
## 现有结果
`target/performance/http2-plain-128m/report.json` 中,Dever 4x16、30000 req/s 的三轮结果为:
- h2c 成功 QPS 29506–29804,服务端约 0.87–0.92 CPU,客户端约 0.89–0.91 CPU;
- TLS+h2 成功 QPS 28673–29865,服务端约 0.91–0.93 CPU,客户端约 0.92 CPU;
- 请求错误均为 0,但存在容量丢弃,因此该档位不能确定是哪一端首先饱和。
## 方案比较
| 方案 | 优点 | 问题 | 结论 |
| --- | --- | --- | --- |
| 多进程客户端 | 调度器天然分片,可跨多个 CPU | 每进程独立直方图,现有分位数无法正确合并;还需拆分 rate、连接和生命周期 | 本阶段不采用 |
| 单进程多线程 | 已有 Tokio 支持;保留单一计数、校验和直方图;改动只在 Python 配置 | 单一调度协程仍可能成为更高档位瓶颈 | 先采用并用结果验证 |
| 引入 h2load 等外部工具 | 成熟、高吞吐 | 新依赖、响应合同和报告格式不同,破坏现有可比性 | 不采用 |
## 结论
当前最小实验不是重写负载器,而是解除 Python 对已有多线程能力的限制。只有在多 CPU 客户端仍显示调度端瓶颈时,才有证据支持后续分片调度或多进程直方图协议。
@@ -0,0 +1,26 @@
{
"id": "http2-ceiling-soak",
"name": "http2-ceiling-soak",
"title": "HTTP/2 ceiling and soak",
"description": "解除 HTTP/2 压测客户端单核限制,测量单核小内存服务的饱和边界、稳态表现与连接恢复耐久性。",
"status": "completed",
"dev_type": null,
"scope": "test/performance + performance docs/spec; reuse existing network_bench and production runtime unchanged",
"package": null,
"priority": "P2",
"creator": "Antigravity",
"assignee": "Antigravity",
"createdAt": "2026-09-13",
"completedAt": "2026-09-18",
"branch": "main",
"base_branch": "main",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": "09-04-dever-language-mvp",
"relatedFiles": [],
"notes": "",
"meta": {}
}