Skip to content

Commit f70ec39

Browse files
AlexStocksOmX
andcommitted
fix(runtime-baseline): make single-case thresholds fail closed
Replace incomplete run-level publishability with a strict single-case checker. Validate frozen policy values and case-specific inputs before evaluating every declared threshold, while leaving manifest conservation, repetition, CV, and provenance to the later controller. Constraint: A single-case Pass is not a publishable baseline-run decision. Confidence: High; boundary tests cover each threshold and isolated mutations prove the resume-drain and PING checks are observable. Scope-risk: Limited to runtime-baseline threshold inputs, schema, fixture assembly, license configuration, and baseline documentation. Tested: WSL cargo test -p runtime-baseline --all-targets; WSL cargo clippy -p runtime-baseline --all-targets -- -D warnings -D clippy::unwrap_used; cargo fmt --all -- --check; SkyWalking Eyes header check; git diff --check. Not-tested: Fixed-host runtime baseline matrix remains deferred until real thresholds and the controller verifier exist. Co-authored-by: OmX <omx@oh-my-codex.dev>
1 parent 19718ce commit f70ec39

6 files changed

Lines changed: 927 additions & 181 deletions

File tree

.licenserc.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ header:
3939
4040
paths-ignore:
4141
- '**/*.md'
42-
- '*.json'
42+
- '**/*.json'
4343
- 'LICENSE'
4444
- 'NOTICE'
4545
- 'Cargo.lock'

docs/performance/storage-runtime-baseline.md

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,27 @@
77

88
- **冻结阈值只能来自固定 Linux/WSL 主机。** 设计规格明确禁止用 Windows / GitHub
99
hosted runner 的跑分数字冻结阈值——矩阵的可重现性依赖固定的内核、文件系统与
10-
CPU 拓扑。因此本仓的 CI 只在固定 Linux 环境执行完整矩阵;本地/Windows 仅用于
11-
开发迭代与 `cargo check` / `clippy` / `cargo test`
10+
CPU 拓扑。当前 hosted CI 只编译 harness 并执行代码检查;完整矩阵未来只能通过
11+
`workflow_dispatch` 在固定环境运行,或由维护者在规定的固定 Linux/WSL 主机执行
1212
- **不在基线未稳前伪造数字。** `tools/runtime-baseline/src/thresholds.rs` 中的常量
1313
当前为占位哨兵值(`f64::NAN` / `usize::MAX` / `u64::MAX` / `i64::MAX`),并标注
1414
`TODO(#351)`。只要任一仍为占位值,`thresholds::all_frozen()` 返回 `false`
15-
`verify_outcome` 会据此把任何 case 判为 `NonPublishable`,杜绝「用占位值假装通过」。
15+
`verify_outcome` 会据此返回 `PolicyUnavailable`,杜绝「用占位值假装通过」。
1616

17-
## 本次 PR 交付了什么(#390
17+
## 本次 PR 的准备工作(Refs #390
1818

1919
建立 #351 量化验收门禁的**阈值冻结机制**本身:
2020

2121
| 文件 | 作用 |
2222
|------|------|
2323
| `tools/runtime-baseline/src/thresholds.rs` | #351 验收所需的冻结基线阈值常量 + `all_frozen()` 哨兵检测 |
24-
| `tools/runtime-baseline/src/verify.rs` | `Outcome` 比对器:`verify_outcome` / `verify_outcome_path`返回 `Publishable` / `NonPublishable` / `Fail` |
25-
| `tools/runtime-baseline/schema/outcome.schema.json` | verifier 期望的 outcome JSON 结构 |
24+
| `tools/runtime-baseline/src/verify.rs` | 严格的单 case threshold checker;返回 `Pass` / `PolicyUnavailable` / `Fail` |
25+
| `tools/runtime-baseline/schema/outcome.schema.json` | 单 case threshold input 的 JSON Schema 2020-12 合同 |
2626
| 本文件 | 方法论与回填流程说明 |
2727

28-
`verify.rs` 的单元测试 `placeholder_thresholds_make_every_case_non_publishable` 是「不伪造
29-
数字」的硬保证:占位状态下任何真实数值都判 `NonPublishable`
28+
单 case 的 `Pass` 只证明该 case 满足冻结阈值,不代表完整 baseline run 可发布。最终发布
29+
结论还必须由 controller verifier 核对 manifest case 集守恒、重复轮次、CV、来源身份和
30+
完整 run outcome。占位状态下 checker 只返回 `PolicyUnavailable`
3031

3132
## 为什么 observer 接线与真实数字是 follow-up
3233

@@ -35,18 +36,19 @@
3536
控制器与 `cases.yaml`。这部分改动进入 `src/common/runtime/`,会拉入 `storage``rocksdb`
3637
必须在能编译/运行 RocksDB 的环境验证——因此作为独立 PR 在 Linux 主机推进。
3738
- **Baseline Results(真实数字冻结)**:在固定 Linux/WSL 主机按版本化 `cases.yaml` 跑完整
38-
矩阵后,把真实数值回填进 `thresholds.rs`再让 verifier 全量判 `Publishable`。仅此 PR 验收
39-
通过后才关闭 #350
39+
矩阵后,把真实数值回填进 `thresholds.rs`再由完整 verifier 聚合全部 case、稳定性和
40+
provenance 证据。只有原始结果、报告和真实阈值满足 #390 Acceptance 后才关闭 #390
4041

4142
## 未来回填流程
4243

4344
1. 固定 Linux/WSL 主机,按版本化 `cases.yaml` 跑完整矩阵(基础吞吐 + value 变体 + 单因素扫描
44-
+ offered-load 4 档 + lifecycle 3 类;每 case 重复 5 次、CV<=5%)。
45+
+ offered-load 4 档 + lifecycle 3 类;性能 case 重复 5 次、lifecycle case 重复 3 次,
46+
CV<=5%)。
4547
2. 将实测值回填 `thresholds.rs`(替换 `TODO(#351)` 占位)。
46-
3. `python3 tools/runtime-baseline/run_baseline.py verify ...``verify_outcome` 全量
47-
`Publishable`
48+
3. 由后续 `run_baseline.py verify` 对每个 case 执行 threshold check,并核对完整 case 集、
49+
重复轮次、CV 和来源身份后产生 run 级发布结论
4850
4. 提交原始 JSON/CSV + 环境清单(内核、CPU、文件系统)+ 摘要;冻结 #351 量化验收阈值。
49-
5. 关闭 #350
51+
5. 满足 #390 Acceptance 后关闭 #390,并在 #350 / #351 中引用结果
5052

5153
## 本地验证(不依赖 RocksDB)
5254

Lines changed: 161 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,173 @@
11
{
2-
"$schema": "http://json-schema.org/draft-07/schema#",
3-
"$comment": "Baseline Results PR 回填真实数字、且 thresholds.rs 全部常量脱离占位哨兵值后,outcome 才可 publishable。本 schema 描述 verifier (src/verify.rs) 期望的 outcome 结构;verifier 使用 serde 反序列化,容忍未知字段以便前向兼容。",
4-
"title": "BaselineOutcome",
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://arana-db.github.io/kiwi/schemas/runtime-baseline/threshold-outcome.schema.json",
4+
"title": "RuntimeBaselineThresholdOutcome",
5+
"description": "Strict input for one case threshold check. A passing case is not a publishable baseline run.",
56
"type": "object",
7+
"additionalProperties": false,
68
"required": [
79
"case_id",
810
"qps",
911
"p99_ms",
1012
"max_latency_ms",
1113
"error_rate",
12-
"queued_plus_running_max"
14+
"queued_plus_running_max",
15+
"cpu_change_ratio",
16+
"rss_change_ratio",
17+
"threads_delta",
18+
"case"
1319
],
1420
"properties": {
15-
"case_id": { "type": "string" },
16-
"qps": { "type": "number" },
17-
"p99_ms": { "type": "number" },
18-
"max_latency_ms": { "type": "number" },
19-
"error_rate": { "type": "number" },
20-
"overload_120pct_error_rate": { "type": "number" },
21-
"queued_plus_running_max": { "type": "integer" },
22-
"storage_gate_pause_ms": { "type": "integer" },
23-
"storage_gate_resume_drain_ms": { "type": "integer" },
24-
"shutdown_drain_ms": { "type": "integer" },
25-
"slow_storage_new_conn_ms": { "type": "integer" },
26-
"slow_storage_ping_ms": { "type": "integer" },
27-
"cpu_change_ratio": { "type": "number" },
28-
"rss_change_ratio": { "type": "number" },
29-
"threads_delta": { "type": "integer" }
21+
"case_id": {
22+
"type": "string",
23+
"minLength": 1,
24+
"pattern": ".*\\S.*"
25+
},
26+
"qps": {
27+
"type": "number",
28+
"minimum": 0
29+
},
30+
"p99_ms": {
31+
"type": "number",
32+
"minimum": 0
33+
},
34+
"max_latency_ms": {
35+
"type": "number",
36+
"minimum": 0
37+
},
38+
"error_rate": {
39+
"type": "number",
40+
"minimum": 0,
41+
"maximum": 1
42+
},
43+
"queued_plus_running_max": {
44+
"type": "integer",
45+
"minimum": 0
46+
},
47+
"cpu_change_ratio": {
48+
"type": "number",
49+
"minimum": -1
50+
},
51+
"rss_change_ratio": {
52+
"type": "number",
53+
"minimum": -1
54+
},
55+
"threads_delta": {
56+
"type": "integer"
57+
},
58+
"case": {
59+
"oneOf": [
60+
{
61+
"type": "object",
62+
"additionalProperties": false,
63+
"required": [
64+
"kind",
65+
"anchor_qps",
66+
"anchor_p99_ms",
67+
"anchor_max_latency_ms"
68+
],
69+
"properties": {
70+
"kind": {
71+
"const": "normal_load"
72+
},
73+
"anchor_qps": {
74+
"type": "number",
75+
"exclusiveMinimum": 0
76+
},
77+
"anchor_p99_ms": {
78+
"type": "number",
79+
"exclusiveMinimum": 0
80+
},
81+
"anchor_max_latency_ms": {
82+
"type": "number",
83+
"exclusiveMinimum": 0
84+
}
85+
}
86+
},
87+
{
88+
"type": "object",
89+
"additionalProperties": false,
90+
"required": [
91+
"kind",
92+
"error_kinds"
93+
],
94+
"properties": {
95+
"kind": {
96+
"const": "overload_120pct"
97+
},
98+
"error_kinds": {
99+
"type": "array",
100+
"uniqueItems": true,
101+
"items": {
102+
"type": "string",
103+
"minLength": 1,
104+
"pattern": "^\\S(?:.*\\S)?$"
105+
}
106+
}
107+
}
108+
},
109+
{
110+
"type": "object",
111+
"additionalProperties": false,
112+
"required": [
113+
"kind",
114+
"pause_ms",
115+
"resume_drain_ms"
116+
],
117+
"properties": {
118+
"kind": {
119+
"const": "storage_gate"
120+
},
121+
"pause_ms": {
122+
"type": "integer",
123+
"minimum": 0
124+
},
125+
"resume_drain_ms": {
126+
"type": "integer",
127+
"minimum": 0
128+
}
129+
}
130+
},
131+
{
132+
"type": "object",
133+
"additionalProperties": false,
134+
"required": [
135+
"kind",
136+
"drain_ms"
137+
],
138+
"properties": {
139+
"kind": {
140+
"const": "shutdown"
141+
},
142+
"drain_ms": {
143+
"type": "integer",
144+
"minimum": 0
145+
}
146+
}
147+
},
148+
{
149+
"type": "object",
150+
"additionalProperties": false,
151+
"required": [
152+
"kind",
153+
"new_conn_ms",
154+
"ping_ms"
155+
],
156+
"properties": {
157+
"kind": {
158+
"const": "slow_storage"
159+
},
160+
"new_conn_ms": {
161+
"type": "integer",
162+
"minimum": 0
163+
},
164+
"ping_ms": {
165+
"type": "integer",
166+
"minimum": 0
167+
}
168+
}
169+
}
170+
]
171+
}
30172
}
31173
}

0 commit comments

Comments
 (0)