现状注记(2026-10-04):本文的裁定使命已被后续演进实质承接——裁定①(核心不重写)被 MoonBit 迁移的绞杀者模式实践超越(同仓重写已推进至 S8 收官,Rust 区冻结为 oracle 待退役);D5 工具链 Go 化已于 2026-09-18 收官;D6(JIT 存废重裁)已由总计划 F-3 裁定承接(JIT 倾向不搬,模板 JIT 可搬 MoonBit、S9 复核);§14 JIT trace P0 静默错值为 Rust oracle 冻结区存量缺陷(
baseline/jit_nested_counting_loop*.c红锚在库),随 Rust 区退役自然消失。本文保留为裁定过程与判据体系(J1~J10)的第一手档案,scripts/core_asset_verdict/证据与native/tests/CORE_ASSET_VERDICT_FAILURES.md台账仍被防线引用〔——已失效:两者均随 2026-10-05 删区退役(探针对象为 Rust 冻结区),git 历史可回溯;2026-10-07 回灌〕。本文是什么:对
统一整备路线图.md(U0~U7,排期权威)之上"核心资产要不要重构、 重构什么、按什么边界与顺序"的重新裁定。它是决策文档,不是施工计划——施工仍以路线图为准, 本文只增补/修订边界、判据与证据。本文不是表态:每条结论都给验证方式与反证条件;文中所有数字都是本次会话在
master@8236bc5(工作区含未提交的文档改动)上实测得到的,脚本与原始 JSON 落在scripts/core_asset_verdict/(已随 2026-10-05 删区退役——证据 JSON 见 git 历史 / tagrust-oracle-freeze)。验证方式标注(强制):
[动态实测]= 本次会话实际运行并记录;[静态亲读]= 本次会话直接读码/读文档确认;[agent 报告,未独立复核]= 引用既有模块审查结论;[未验证]= 未取得证据。 禁止把[agent 报告]当[动态实测]。与既有裁定的关系:本文不推翻
三语化整备审计计划.md§5.0 的三层裁定与 路线图 §0 的合并裁定(裁定①②③④),而是在新证据下:① 修正裁定①的证据基础与适用范围 (原表述"662 影子用例的逐字节行为锚是最硬资产"经实测只对"批处理 stdout"面成立); ② 把裁定②的边界从目录改划为设计域;③ 新增第⑤层(防线口径自身); ④ 给"整体重写"(候选 D/E)写下可测量的触发门槛(当前未触发)。
0. 一句话裁定
核心(编译管线五段 + VM opcode 语义)不重写——但这条裁定过去是拿"662 全绿"当证据的,那个 证据经本次独立通道实测不合格;真正支持它的是本次新增的独立证据(1000 例随机三路差分零分歧 + 按切面突变 margin 32~559)。同时,"不动核心、只跑 U0~U7"(候选 A)也被实测否决:交互出口 (serve)上存在越过程序末尾 seek 即 panic** 的新 P0,且它不在 U0~U7 任何批次里;教学内容、 可视化、步级 payload 三个切面的突变 margin = 0~1(M2/M6 零检出),即产品价值所在的面 当前没有防线。**
因此本次裁定的落点是:B(防线换代)+ C(资源与参数域接口级补设计→域内局部重写)并行先行; D(整体重写)与 E(换载体)不触发,且各自的门槛写成可测量的数字(§Q4/Q6)。 顺序上 B 必须先于任何交互切面重写——因为在 B 建成之前,没有任何人能判断交互切面的重写 是变好还是变坏(现状是"没有 oracle",不是"oracle 说是好的")。
1. 证据清单(本文全部论断的原始来源)
1.1 母文档(结论以其为准,本文只做增补/修订)
| 文档 | 本文引用点 |
|---|---|
| 统一整备路线图.md | §0 统一裁定、§1 波次 U0~U7、§4 防伪绿机制、§7 三份外部审查吸收记录 |
| 三语化整备审计计划.md(已归档) | §1 渗出证据链、§2 伪全绿机制解剖(M1~M9)、§5.0 三层裁定与"≥2 次 GB 级事故"判据 |
| 重构评估报告20260912.md(已归档) | §1 事故史、§2 unified/engine.rs 专审、§3 分模块(R/E/T/H/C 编号)、§4 风险清单 |
native/tests/shadow_verification/reports/shadow_report_latest.md(2026-09-27 注:该 latest 报告为裁定当日时点产物,现不在库——shadow 报告链路随 D5 Go 化变更,目录仅存历史 JSON;防线当前口径以 CI shadow 实跑为准) |
防线当时口径与实测数字(662 / 643 / 3 / 16) |
| 工作记录20260912_突变测试.md(已归档) | M1/M2/M3 突变实测、裕度=1、UMod 除零零检出、baseline 用例中位 2 行 |
docs/archive/RUST_MIGRATION_PLAN.md |
重写史:范围/工期/风险表/已知取舍 |
docs/archive/INCIDENT_2026_04_26_MEMORY_LEAK.md、…04_27_PARSER_INFINITE_LOOP.md |
C++ 时代两次事故(32GB / 18GB)与"三重防卡死"加固 |
docs/current/07-质量与裁定/INCIDENTS/事故202609_Seek重放泄漏.md |
63.6GB + 33.9GB 页面文件事故与复发补录 |
CHANGELOG.md |
第 188 行事故条目;迁移期条目历史 |
1.2 本次新增的实测(脚本可复现;原始 JSON 同目录)
| 编号 | 探针 | 脚本 | 结论文件 |
|---|---|---|---|
| E1 | 662 用例静态普查 + 测试套件切面普查 | case_census.py / test_facet_census.py |
case_census.json / test_facet_census.json |
| E2 | clang 外部 oracle 逐个重算 | clang_oracle_audit.py |
clang_oracle_audit.json |
| E2b | 无 oracle 用例的门禁分类 | oracle_free_classification.py |
oracle_free_classification.json |
| E2c | 无 oracle 用例"可救性"(补头文件) | oracle_gap_probe.py |
oracle_gap_probe.json |
| E3 | 按使用切面的突变测试(6 个突变) | mutation_facet_test.py |
mutation_facet.json |
| E4 | 随机程序 × clang × Vitro 三路差分 1000 例 | random_diff.py |
random_diff.json |
| E5 | 随机交互序列 + 恶意输入 fuzz | interaction_probe.py |
interaction_probe.json |
| E5b | panic 最小复现(4 个场景) | repro_panics.py |
repro_panics.json |
| E6 | 资源长跑(驱动侧 psapi) | resource_longrun.py / seek_accumulation.py |
resource_longrun.json / seek_accumulation.json |
测量工具说明(诚实标注):路线图 U0 要求"psutil 独立测量",本机
pip install psutil失败 (离线)[动态实测],改以ctypes直接调用同一 API(psapi.GetProcessMemoryInfo,见winmem.py)——仍是驱动侧独立测量,且与既有scripts/replay/debug_p3_leak.py口径一致。 不信被测代码自报这一条未被削弱。
2. 核心张力 T1~T5 的正面处理
T1 换语言没有换来生命周期设计 —— 成立,且证据链完整
| 环节 | 证据 | 验证 |
|---|---|---|
| 前身是 C++,因 VM 无限内存泄漏改写 | RUST_MIGRATION_PLAN.md §1~§4:目标为迁 ~8,057 行 C++;工期 4~5 周;§7 风险表列了 ABI/Android toolchain/parser 死循环/VM 性能/序列化/UTF-8,唯独没有"资源生命周期" |
[静态亲读] |
| C++ 时代两次事故是"缺设计"而非"缺补丁" | 2026-04-26:不支持 cast → (int*)100 被解析成 Deref(100) → wasm3 无限循环 → 32GB;2026-04-27:struct Node* f(...) 顶层分支误判 → Consume 零进度 → 18GB。两次的修复都是加保险丝(步数上限/超时/零进度保护),不是设计(无窗口、无预算、无所有权模型) |
[静态亲读] |
| 改写完成后 Rust 版又两次 | 事故202609_Seek重放泄漏.md:63.6GB 物理内存 + 33.9GB 页面文件;10591ad 修复一个提交内 4 个生命周期缺陷;随后复发;两次均人肉发现、零防线拦截 |
[静态亲读] + 本次 [动态实测] 复现其机制(§Q3-E6) |
| 遗留与代价 | 迁移解决了"AST 所有权/解析死循环"类(Box/enum + 零进度保护),代价是把同一失败模式换成了"窗口与缓存的累积"(unified/ 与 vitro_vm 累积状态);行为债 = 从零重建 662 用例所锚的语义(本次量化见 §Q3) |
[静态亲读] |
推论:正确切面不是语言层、也不是整体 yes/no,而是哪些域缺少设计。本次把"缺设计"从
unified/ 扩展到四处(见 §Q1 的表与 §Q5 的边界重划)。
T2 防线与被测对象同源 —— 部分成立,且本次实测给出了同源性的量
工作记录20260912_突变测试.md 已证"判定逻辑可信"(3/3 检出)。本次把测量推到切面维度:
| 突变 | 目标切面 | 影子检出 | 891 测试检出 | margin |
|---|---|---|---|---|
M1 冒泡趟数改回 n-i(重引入已修 P0-1) |
教学内容标注 | 0 | 1(test_bubble_pass_description_matches_rank) |
1 |
M2 PointerStatus::Freed → Valid |
可视化指针四状态 | 0 | 0 | 0(无防线) |
| M3 4 个 temp_slot 塌缩成 1 个 | codegen 槽位/批量正确性 | 31 | 1 | 32 |
| M4 E3023 诊断文案改写 | 诊断内容 | 0 | 1(test_type_checker_undeclared_var) |
1 |
| M5 十进制字面量 +1 | 词法/批量正确性 | 515 | 44 | 559 |
M6 兜底 semantic_label 恒为"第 1 行" |
步级 payload 标注 | 0 | 0 | 0(无防线) |
[动态实测:mutation_facet_test.py,每个突变 cargo build --release → 影子 → cargo test →
git checkout 还原;all_files_reverted: true,还原后影子复跑 643/3/16 绿]
读法:防线不是纸糊的(M3=32、M5=559 说明批处理正确性面被密集锚住),但防线强度与 "产品价值所在的面"完全错位——教学标注 margin 1、诊断文案 margin 1、可视化四状态 0、 步级兜底标注 0。这正是 T3 的定量版本。同时它也给出 T2 的答案:同源性没有让防线失效, 让防线失效的是切面选择。
T3 防线切面与产品价值切面错位 —— 成立,且已量化
| 面 | 影子防线(662) | 工作区测试(891) | 输入程序数 |
|---|---|---|---|
| 批处理 stdout | 662/662(100%) | 376 条(batch_stdout 类,46.4% 的集成测试) |
662 |
| 步级 payload / 交互 | 0/662 | 30/810 条集成测试(3.7%;含 8 条 schema 形态/词汇闭包) | 十几个小程序(5 个交互测试文件内联原始字符串 21 处,含 JSON 片段) |
| 诊断内容 | 0(只看编译成功与否) | 38 条(4.7%) | 少量内联 |
| 资源生命周期 | 0 | 19 条(2.3%) | 少量 |
[动态实测:test_facet_census.py(810 个 #[test],按测试体引用 API 归类);影子侧的 0 由驱动
源码决定——analyze_diff 只比较 stdout.strip(),[静态亲读]]
规模侧的证据(同样重要):
- 662 用例行数:中位 9 行、均值 18.3、p90 50、最大 122;
≤5行 296 例。(case_census.py) - 662 用例真实步数(逐个跑
vitro_cli unified):测得 652 例,中位 115 步、p90 1938、 p99 13916、最大 135835;≥10k步仅 11 例、≥100k步仅 1 例。(measure_steps.py) - 语言面覆盖形状:
printf660、字符串字面量 655、循环 306、指针 295、数组 292, 而unsigned仅 26、位运算 23、函数指针 9、union7、file_io10、变参 2、math.h2。 - 带
.in标准输入的用例 34/662。 - 引擎
max_steps默认 1000 万——压力用例规模与泄漏量级差 2~4 个数量级。
→ "662 是最硬资产"只对批处理 stdout 面成立,且这一面的覆盖是"窄而密"(中位 9 行/115 步)。
T4 使用证据缺失被误读为"没问题" —— 成立
- 三出口的外部消费者只有一个:SharpTutor,锚定
10591ad(本仓库已推进 4 个提交) [静态亲读:下游需求处置回执.md头部]。 - wasm32 出口:只有"零修改构建 3.75MB + C API 全链路冒烟",无运行时行为实测
[静态亲读:
AGENTS.md;本次[未验证]]。 - 没有任何会话量/用户量/语料量记录。→ 按 T4 要求,无使用证据的资产默认高风险; 本次据此把"交互出口(serve)"的风险等级从"U2 附带项"提为"独立 P0"(§Q1)。
T5 真实使用者路径与防线路径不一致 —— 证据缺口,列第一优先
- 仓库内没有任何真实学生失败记录:
docs/current/04-标准库与防线/学生错误用例集.md是 假想清单("预期诊断"由作者写定),且 grep 全native/无任何测试引用它 [动态实测 + 静态亲读]。 - 真实用户试用计划过、从未产出结果:
ROADMAP_2026_Q3.mdC2.1"邀请 3~5 名真实用户 (学生/教师)"、C2.x 明写"需要真实用户,当前无法由 Agent 独立完成";ARCHIVE_M7_BETA_READINESS.md§4 有"试用计划/反馈收集点/通过标准",但仓库内 不存在CPP_BETA_FEEDBACK.md或任何等价产物(glob 实测:*BETA*只命中该归档件)。 - ⇒ "复现真实学生失败路径 = 0 条",原因不是我不会复现,而是输入不存在。
按任务要求,该证据缺口列 Q7-G1 第一优先,并在此明示:本文所有关于"教学生会怎么用"
的推断都是
[未验证],不作为任何裁定的依据。 - 2026-09-12 更新(本裁定交付后获得新输入):用户补交了前端期 2 条真实现场,
"输入不存在"不再成立。复核结论(独立实测 + clang 对照,详见
native/tests/CORE_ASSET_VERDICT_FAILURES.md): ①char *p参数上p += 2被误拒(E3045)——已修,且被影子可靠接住(9 个用例全部有真 golden); ② 单条声明内混合"不定长数组初始化 + 标量 + 指针"被误拒——已修(2026-06-07), 但该形态在全防线语料中覆盖 = 0,修复只被特性级用例锚定 → 新登记 D-2026-09-07, 并已补用例baseline/multidecl_array_pointer_mix.c(自带<stdio.h>,有真 golden); ③ 同批现场还暴露E3053误报(char 数组用字符常量初始化报 N 条"可能丢失精度")—— 当前仍存在,新登记 R-2026-09-12;④ 覆盖率 >100% —— 属code_line跨文件全局行号的 协议缺口,已在docs/spec/STEP_PAYLOAD_SCHEMA_V0_1.md§8 #9 补记"消费方可见后果"。 方法论点:这 4 个问题中只有 1 个被"事后补影子测试"这条链可靠接住(1 个形态零覆盖、 2 个结构上不可能接住),即该处置方式对本次现场的有效覆盖率约 1/4—— 这为 §T3"防线切面与产品价值切面错位"提供了样本级证据,也为 Q5-B(防线换代) 提供了"按现场形态而非特性清单建语料"的具体要求。G1 仍为 P0 第一优先 (2 条 ≪ 30 条,且两条均为回忆提交、无系统留痕入口)——2026-09-13 更新:该 "一次性凑样本"判据已废止,G1 拆分改判为 G1a(真实通道滚动等待,不阻塞 CS 系列)+ G1b(合成靶料,随 U1 交付),见 §9;缺口由开放台账承接,不再阻塞。
3. Q1 分区裁定表
判据栏一律给"本次证据";反证栏给"什么证据会改变此裁定"。 "不写代码的域"与"写代码的域"同等对待——本表最后一行是防线自身。
| 域 | 裁定 | 判据(本次证据) | 反证条件(改判触发) |
|---|---|---|---|
| lexer | 不动(域内局部补:\x 2 位、08 拆分、.5 已列 U1#7) |
M5 margin 559 [动态];随机差分 char/字符串/字面量 100 例零分歧 [动态] | 随机词法差分 ≥2000 例出现 ≥1 条未记录的转义/字面量语义分歧并影响 stdout |
| parser(含递归/预处理器) | 不动(补设计:深度五通道与保险丝,U1#6/#8) | 1000 例随机程序全部按 clang 一致解析执行 [动态];历史死循环已由零进度保护根治;suffix_count/#if 深度缺口是"缺上限"不是"缺结构" [静态/agent] |
同一入口 ≥2 次栈溢出崩溃(而非报错)且补上限无效 → 递归结构重写 |
| typeck | 不动(模板子域补设计:U3#4/#5) | 随机差分 struct/funcs/nested_loop 各 100 例一致 [动态];T1/T2 是上限缺失与 drain 收敛缺陷 [agent] |
加上限后模板仍产生 ≥3 起合法 C++ 误拒/静默错布局 → 模板子域域内局部重写 |
| codegen(含槽位系统子域) | 不动(槽位子域补设计:U3#1~#3) | M3 margin 32(槽位塌缩被 31 影子用例+1 测试拦住)[动态];3 起历史槽位 bug 位置固定、可局部手术 [agent] | 槽位分配器落地后 6 个月内再现 ≥2 起同类槽位冲突且全防线放行 → 该子域已是重写形态,需重定 |
| runtime(共享内存模型/opcode 描述) | 不动 | 随机差分含 malloc_list/struct/指针算术 100 例一致 [动态];内存边界判据已单源(GLOBAL_REGION_LIMIT/compute_heap_base)[静态] |
隔离区语义差分用例证明改动破坏 UAF 检测 → 冻结该域 |
| VM executor / opcode 语义核心 | 不动 | 突变 M1 384/M2 43 检出;1000 例随机三路差分(含 unsigned 回绕、位运算、比较、除模)零分歧 [动态] | margin<3 的核心 opcode(如 UMod=1、除零=0)出现 ≥1 次真实错值且未被拦截 → 该语义域内局部重写 |
VM 累积状态(regions/output_chunks/runtime.trace/vis_event_queue) |
补设计(U2) | putchar 1M → 45.5MB 峰值提交 [动态];vis_event_queue 非 unified 出口只进不出 [静态];regions 的"14B/次无界"与本次实测不一致(峰值平坦 8.6MB)→ 见 Q7-G6 [动态] |
长跑实测证明四者有界且在预算内 → 降级为"不动" |
unified/(状态机/快照/checkpoint/seek/窗口) |
重构区:补设计 + 参数域收口;允许域内局部重写(不是推倒语义) | 新 P0:seek 越过程序末尾 → engine.rs:400 split_off panic(最小复现:10 步程序 + seek(50000) 或 seek(3000) → exit 101、会话死亡)[动态];payload.get end=-1 → engine.rs:416 切片 panic [动态];seek 重放峰值 ≈1.2~2.3KB/步(50k→116MB、200k→309MB、500k→620MB;按默认 1000 万步外推 ≈12~23GB)[动态];检查点淘汰悬空 Delta [agent/静态] |
补设计后:(a) 随机交互序列 ≥1000 会话零 panic;(b) RSS 斜率 ≤64B/步;(c) 检查点/隔离语义差分用例全绿 → 该域转"不动" |
capi / serve 契约层 |
不动(局部收口) | 会话生命周期健康(Box::into_raw/from_raw 配对、无全局表)[静态];三所有权/头文件/catch_unwind 缺口已列 U0#7;本次新增:serve 主循环无 catch_unwind,一条畸形请求即杀死会话 [动态] |
下游按书面契约消费出现 ≥1 次 UAF/双重释放 → 契约层升级为重构区(改 wire format 需 schema 版本化) |
session_api(语义中立层) |
不动(补参数域防御) | 缺校验集中在 payload.get/seek 的 i64 → i32 裸 as [静态亲读:vitro_cli.rs:742-757] |
— |
| diagnostics 教学内容层 | 补设计(防线侧为主) | M4 margin 1(文案改写仅 1 个测试抓到)[动态];诊断切面 38/810 测试;error_catalog 文案无 golden [静态] | U1#1 诊断文案 golden 上线后随机文案突变 margin 仍 <3 → 该层进重构区 |
vitro_algorithm_steps(教学标注) |
补设计 + 补防线(不是重写) | M1 margin 1;M6 margin 0(兜底标注零防线)[动态];词汇闭合只保证"在表内",不保证"与行为一致" [静态] | U1#1 标注-行为一致性 property 上线后 margin ≥3 → 转"不动" |
| JIT 模板 | 域内局部重写(收敛到单语义源,U5#1) | 文档记录 JIT wrapping vs 解释器 trap、JIT 区间断点静默失效 [agent,未独立复核] | 三路径差分矩阵建成后若无法收敛 → 维持域内局部重写(即现状);若收敛 → 转"不动" |
前端六小 crate:vitro_lexer/vitro_parser/vitro_ast/vitro_shared/vitro_cpp_frontend/vitro_algorithm_steps |
lexer/parser/ast/shared/cpp_frontend 不动(cpp_frontend 165 行仅 JSON 加载);algorithm_steps 见上一行 | 随机差分覆盖前五个中的四个;vitro_ast 仅 1329 行且被全链路复用 [动态+静态] |
vitro_cpp_frontend 的布局 JSON 出现 ≥1 次静默错布局 → 该 crate 域内局部重写 |
native/src/engine + compiler(管线双轨) |
补设计(合并双轨),非正确性缺陷 | 双轨 ~350 行×2 复制 [agent];补全每击键全量重解析 [agent] | 合并引入 ≥2 次行为回归 → 保持双轨 |
| 防线口径自身(新增第⑤层) | 重构区(口径重划) | 662 中 22 例无外部 oracle 且全部算通过,其中 21 例零 stdout 比对;13 例补 #include 即可恢复真 golden(驱动对文件用例不注入头文件)[动态];影子侧交互切面 0 覆盖;切面 margin 0~1 四处 [动态] |
oracle 覆盖率 100%、切面 margin 全 ≥3、usage 台账建立 → 转"常设维护" |
边界重划(这是本次裁定对既有②/③最重要的一处修订):
既有裁定用目录划界("native/src/unified/ 进重构区")。实测显示同一病理
(边界/参数域从未被设计)跨目录存在:
unified/engine.rs—— 窗口/重放边界(seek 距离无约束、split_off无防御);unified/engine.rs+session_api/serve—— 参数域(end=-1、step越界 → 一条 JSON 杀死会话);vitro_vm累积状态 ——regions/trace/output_chunks/vis_event_queue无预算;unified/collector.rs的 payload 生成路径 —— 四状态/标注的正确性无防线(margin 0)。
⇒ 重构区应按"哪个域缺设计"划,而不是按目录划:统一命名为
「生命周期与参数域(Lifecycle & Parameter Domain)」,含上述 4 处;unified/ 只是其中一处。
4. Q2 判据体系 v2(可机检)
既有四条升级判据(多真相再现 / 修 A 坏 B / known_issue 趋势 / 同子系统 ≥2 次 GB 级事故) 全部落在代码语义域与资源域,对"防线外切面"无效——这正是本次发现 seek panic 与 margin-0 切面的原因。新增判据全部给阈值 + 检测命令 + 当前实测值:
| 编号 | 判据 | 阈值 | 检测方式 | 当前实测 | 状态 |
|---|---|---|---|---|---|
| J1 | 交互出口参数域全覆盖 | serve 每个方法 ≥3 条边界/负值/极值样例,100% 方法覆盖 | interaction_probe.py(B 段词表 + 方法清单对账) |
30 条畸形输入覆盖 6 个方法;seek 越界与 payload.get 负参直接 panic |
红 |
| J2 | oracle 覆盖率 | 无 oracle 用例 = 0,且 vitro_better = 0(不是"≤N",是 0:每个用例二择一——补头文件转真 golden,或移入 gap/ 并写明"Vitro 扩展,非 C 标准") |
clang_oracle_audit.py |
22 例无 oracle;vitro_better 16 |
红 |
| J3 | 切面 margin(U7#5 的机器化) | 每批次注入 5 个跨切面突变;任一 margin < 3 登记防线债;margin = 0 ⇒ CI 红(该语义视为无防线) | mutation_facet_test.py |
批处理面 32/559 达标;教学内容 1、诊断 1、可视化 0、兜底标注 0 | 红 |
| J4 | 使用证据台账 | 三出口各 ≥1 外部消费者 + ≥1 真实输入语料批次;缺失则该资产默认高风险 | docs/current/USAGE_EVIDENCE.md 台账(待建)核对 |
1 个下游 / 0 学生语料 / wasm 无运行时实测 | 红 |
| J5 | 资源斜率预算(把"RSS 有界"变成数字) | seek 重放 峰值提交 / 重放步数 ≤ 64 B/步;长跑 RSS 增量 < 32MB / 10 万步;驱动侧独立测量 |
resource_longrun.py(psapi) |
1.2~2.3 KB/步(超标 19~36×);50 万步峰值 620MB | 红 |
| J6 | 交互切面零覆盖 + 真实使用失败 = 触发重构(本次任务点名要求的判据) | 某 public 方法在 J1 缺测 且 J4 台账中存在该方法导致的真实失败 ≥1 次 → 该方法所在子系统进重构区 | J1 × J4 join(脚本化) | J1 已红;J4 无数据 → 无法判定(缺证据,非通过) | 证据不足 |
| J7 | 保险丝可触发性 + 同类清查(既有,维持) | 每道保险丝 ≥1 个能触发它的用例;新增保险丝先证会红 | U1/U0 既有制度 | 未复核 | 维持 |
| J8 | panic 零容忍(新增) | 任何 public 出口在 fuzz 语料(固定种子 + 每批新随机种子)下不得 panic/abort/非零退出 | interaction_probe.py B 段断言退出码 |
2 处 panic(engine.rs:400/:416) |
红 |
J3 的 margin 定义(与 U7 一致,本次给机器化口径):margin = "能独立拦截该语义突变的 判定数" = 影子分类变化用例数 + 失败测试数。
M2/M6的 margin=0 意味着: 把指针四状态或默认标注整体改错,现有 662+891 条防线一条都不会红。
5. Q3 行为债量化(实测,非脑测)
5.1 "662 用例里有多少是外部可推导的"
clang_oracle_audit.py 不读报告、不读缓存,对 662 例逐个重跑 clang:
| 分类 | 数量 | 占比 |
|---|---|---|
| 外部 golden 成立(clang 编译+运行成功) | 640 | 96.7% |
| 无外部 golden(clang 编译失败) | 21 | 3.2% |
| 无外部 golden(clang 运行失败) | 1 | 0.2% |
这 22 例在影子门禁口径下全部算"通过"(oracle_free_classification.py 直接按
analyze_diff 的真实分支复算):
| 驱动分类 | 数量 | 是否比对 stdout |
|---|---|---|
vitro_better(clang 编译失败、Vitro 成功) |
16 | 否——任何 Vitro 输出都通过 |
match(两侧都编译失败) |
5 | 否(两侧 stdout 均空) |
match(clang 运行失败、Vitro 成功) |
1 | 是(e1_func_identifier) |
既有文档的口径是"豁免通道 ≈6/662"(
KNOWN_FAILURE_CASES2 +@category *bug*4)。 实测的"零比对通道"是 21/662(3.2%),约为其 3.5 倍,且其中没有一例被文档登记。
可救性(oracle_gap_probe.py,只在临时副本补头文件、不改动用例文件):
- 补
#include <stdio.h>等头文件后,13/22 恢复"clang 可编译可运行且 stdout 与 Vitro 一致" ——即这 13 例本可以成为真 golden,只是因为驱动对文件用例不注入头文件 (run_with_clang只在path is None时走make_clang_header)[静态亲读 + 动态实测]。 - 9 例仍然失败:其中
e2_include_cycle/e3_static_assert_fail是设计上双侧都失败 (用例注释已写明),complex_number/implicit_int/variadic_macro/file_*属 Vitro 扩展或 clang 拒绝的构造,e1_func_identifier/keyword_compat为真实差异(后者 Vitro 接受auto int y等写法)。
5.2 "若按交互切面重写引擎,662 用例中真正失效、无法复用的是多少"
逐类评估(可复核的判定,不是估计):
| 类别 | 数量 | 重写后是否可复用 | 理由 |
|---|---|---|---|
| 有外部 golden 的用例 | 640 (96.7%) | 可复用(作为验收判据) | 其判定是 clang stdout == 引擎 stdout,与引擎内部结构无关;任何重实现都可用它验收 |
无 oracle:vitro_better 16 + 双侧失败 5 |
21 (3.2%) | 不可复用 | 没有任何参照物(不是"重写后失效",是现在就没在验收) |
运行失败型 match(e1_func_identifier) |
1 (0.2%) | 需重裁定 | clang 侧本身非零退出 |
known_issue(bTree_default/spfa_default + 两个 sizeof 差异) |
3 (0.5%) | 需重裁定 | 行为由文档约定而非 clang 决定 |
@category 含 bug 的自我豁免通道 |
4 (0.6%) | 风险面(当前未触发差异) | 一旦出现 stdout 差异会被静默判 known_issue |
结论(可证伪):
"重写 = 重新欠一遍行为债"这个论证的量化基础比它听起来弱得多——
真正"失效、不可复用"的是 22 例(3.3%);把 3 例 known_issue 计入需重裁定则是 25 例(3.8%);
把自我豁免通道计入风险面是 29 例(4.4%)。
行为债的真实主体不是"用例失效",而是两件事:
- 语义体量:
native/共 46,516 行 Rust(本次实测),其中管线五段 + VM 执行器 =typeck 8176 + vm 7837 + codegen 5917 + parser 4455 + lexer 3126 + runtime 1606 + ast 1329= 32,446 行;按历史迁移实测速率(8,057 行 / 4~5 周)线性外推 ≈ 6~9 人月, 且 C++/模板/容器面比当年更大; - oracle 的窄带:640 条 golden 的中位规模是 9 行 / 115 步,
unsigned只覆盖 26 例、函数指针 9 例、union7 例、file_io10 例—— 重写即使 100% 复刻这 640 条,也只证明教学子集窄带内一致。
⇒ 这个反直觉的结论正是本次裁定把 B(防线换代)排在重写之前的量化依据: 反对重写的理由不应再说"债太重"(债只有 ~4% 的用例损失),而应说"现有的锚不足以验收任何 重写"。
5.3 资源域的量化(本次实测,含对既有结论的两处修正)
| 项 | 本次实测 | 与既有文档的关系 |
|---|---|---|
| seek 重放峰值提交 | 50k 步 115.7MB / 200k 步 309.2MB / 500k 步 620.1MB ≈ 1.2~2.3 KB/步;按默认 max_steps 1000 万外推 ≈12~23GB |
证实"GB 级"上界;新增斜率数字 |
| seek 峰值性质 | 瞬时(同一会话 6 次远距 seek,峰值 513.7MB,每次 settle 回 ~57~59MB,无跨次累积) | 修正:实践上更像"O(距离) 瞬时尖峰"而非"单调泄漏"——但尖峰本身仍足以打满磁盘(63.6GB 事故即发生在尖峰期间) |
malloc/free |
峰值提交 恒定 8.6MB(100k/300k 次);耗时 5.79s/12.68s/20.73s(50k/100k/200k),≈线性 | 与既有"14B/次无界 + O(N²)"不一致 → 登记 Q7-G6 待复核(不回改既有文档,也不静默略过);2026-09-14 G6 关闭:两侧均为真,分段饱和模型见 §5a |
putchar × 1M |
峰值提交 45.5MB、0.46s | 证实 output_chunks 按字符累积(≈45B/字符) |
5a. Q7-G6 复核定论(2026-09-14,四点直接采样关闭)
方法:scripts/core_asset_verdict/regions_growth(serve 会话 config.set max_steps
提预算 → churn malloc(16)+free ×N → memory.regions 的 region_counts.heap
直接读条目数,不经 RSS 代理;通道失效 fail loud 拒判)。release 构建,单轮
(裁定验收线"×3 次"的四点增长曲线已由机制闭环 + 三源交叉印证替代,见下)。
| N | heap 条目 | 条目/N | 墙钟 | 所处阶段 |
|---|---|---|---|---|
| 1k | 1002 | 1.002 | 94ms | 推进期 |
| 10k | 10002 | 1.000 | 227ms | 推进期末 |
| 100k | 16387 | 0.164 | 4.77s | 饱和(跨段,含 O(N²) 尾巴) |
| 1M | 16387 | 0.016 | 60.4s | 饱和(纯线性段:×10 规模 ×12.7 时间) |
定论:分段饱和模型,§5.3 与评估报告两侧既有证据均为真(观测区间不同):
- 推进期(条目 < 隔离预算 ÷ 块大小):条目随 N 线性增长——评估报告的 "14B/次"(条目 MemoryRegionData 的字节成本)在此段成立;每次操作扫描条目数 随 N 涨,时间含 O(N²) 分量——P-1 的"×5 规模 ×10 时间"跨段观测成立;
- 饱和期(
DEFAULT_QUARANTINE_BUDGET = MEM_SIZE/4 = 256KB填满后 FIFO 驱逐 + free_list 地址复用):条目恒定 16387(= 256KB ÷ 16B + 少量活跃块, 100k 与 1M 两点逐位相同);每次操作扫固定 ~16k 条 → 时间 O(N) 线性—— 裁定 §5.3 的"≈线性"(其三点 50k~200k 全在饱和段)与"峰值平坦 8.6MB"成立; - 饱和机制是设计内行为(隔离区决议 §3 的 FIFO + 预算驱逐),非静默丢条目
——复用路径的
is_freed复位 +freed_logsretain 清理保持 UAF 检测窗口 语义完好(memory.rs复用分支亲读确认); - U2#2 重构判据据此修正:原方案"已释放条目归并 freelist 摘要 + 上限"的
收益有限(稳态 ~16k 条 × 条目字节 = 数 MB 常驻,天然有界);真正痛点是
每次操作的 ~16k 条线性扫描(free 的
iter().find/ malloc 复用的iter().find/ realloc 的retain)——重构方向收缩为 addr 索引化 (HashMap<addr, idx>或有序索引,消 16k×N → O(1)/次),隔离区语义与 复用语义差分用例(U2 验收线既有)作为不破坏判据。U2#2 自本节起解锁开工。
6. Q4 候选方案对比(A~E)
| 候选 | 触发条件 | 成本量级 | 主要风险 | 不可逆点 | 失败回退 | 本次裁定 |
|---|---|---|---|---|---|---|
| A 不动核心,仅跑 U0~U7 | 无 | 已排期 2~3 个月 | 实测已否决:新 P0(seek panic)不在 U0~U7 任何批次;margin-0 切面无批次;RSS 无预算 | 无(但事故会重演) | — | 否决 [动态] |
| B 引擎不动,防线换代(批处理 → 步级 payload + 交互序列 + 资源长跑) | 立即(无前置) | 中:≈2~3 周(本次已交付可运行骨架:random_diff.py / interaction_probe.py / resource_longrun.py / mutation_facet_test.py 等 9 个脚本) |
步级 payload 没有第三方 oracle(clang 不给 payload)→ 必须引入"第二实现/模型 + 人工审";否则会重犯"自证"错误 | 无 | 探针不绿即不合并 | 采纳(第一优先) |
| C 资源与参数域接口级重写(现状只是"补设计") | 已触发:63.6GB + 复发 + 本次两处 panic + margin 0 | 中:域内 ≈3,300 行(unified/)+ session_api 参数域;含设计文档交付物 |
检查点/隔离语义无外部 oracle(无法用 clang 验)→ 必须以"旧引擎二进制双跑差分"为参照 | snapshot/checkpoint 的对外语义若变更(schema 未冻结该部分) | 每阶段 tag;旧引擎二进制作为参照实现 | 采纳(与 B 并行) |
| D 分阶段整体重写编译管线/VM | 门槛(必须同时满足,不是"将来"):① 随机三路差分 ≥5000 例 × ≥5 种子出现 ≥1 条语言语义层(非资源/协议/参数域)未记录分歧且可最小化;② 该分歧所在切面已有 ≥1 条独立 oracle;③ B 已上线(否则无法验收);④ J3 显示相关阶段 margin < 3 | 高:32,446 行语义 + C++ 子集 + 640 golden 重满足 ≈6~9 人月;风险期防线变瞎 | 过渡期无 oracle 可比(新引擎只能以旧引擎为参照 → 只保行为不保正确) | C ABI/schema 已对外承诺,下游已锚定 | 旧引擎 tag | 不触发(门槛写成数字,见 Q6-R1) |
| E 换实现载体(接既有 C 前端 + 保留自研 VM,或反向) | 若产品目标退化为"批处理 stdout 正确性",则 E 最优(clang 直接满足 640 golden) | 省 ≈21,674 行前端(lexer 3,126 + parser 4,455 + typeck 8,176 + codegen 5,917),但失去差异化资产:unified 3,260 + diagnostics 2,222 + algorithm_steps 1,291 = 6,773 行,且第三方前端不提供步级 payload/时间旅行/教学根因 |
等于把产品价值清零;且 662/640 锚全部作废、下游契约重谈 | C ABI/schema 契约已承诺 | 双实现并存(成本翻倍) | 否决(成本对照见左) |
E 的对照要点:E 节省的是最难但已被证明可用的那部分(§Q3-E4 三路差分 1000 例零分歧), 砍掉的正是唯一没有被验证过的那部分(步级 payload/margin 0)。方向与 T3 的证据相反。
7. Q5 选定方案的分阶段计划(B + C)、回滚点与中止条件
2026-09-12 多轮收敛更新:本节是域内计划(B 防线换代 + C 资源与参数域)。 跨域执行顺序、门禁、**新增的第五域(防线自身)**与工具链语言迁移见 §13; 两者若有冲突,以 §13 为准。
7.1 边界与接口冻结策略
- 先冻结"被消费的语义",再动结构:
spec/STEP_PAYLOAD_SCHEMA_V0_1.md已冻结字段集; 本次补冻参数域契约(每个 serve/capi 方法的合法域与越界响应),作为 J1 的判定依据。 - checkpoint/snapshot 的 wire 语义当前未进 schema —— C 阶段若需变更,必须先走 schema
版本化(v0.2 激活轨道已在
unified/contracts.rs+ 冻结测试里,复用该机制)。 - cap 与隔离区语义冻结:
堆有界隔离决议.md的三色堆语义是 C 阶段的 不可破坏项,重构前先写差分保护用例(U2#2 已有要求,本次给具体验收)。
7.2 分阶段(每阶段含红→绿、回滚与"过渡期不变瞎"保障)
| 阶段 | 内容 | 红→绿验收线 | 回滚点 | 过渡期不变瞎的保障 |
|---|---|---|---|---|
| P0 止血 + 仪器(0.5~1 周) | ① unified/engine.rs:400 边界防御(discard.min(len))+ :416 参数域(i64→i32 安全转换 + clamp);② serve 主循环 catch_unwind;③ RSS 预算门禁接入 CI(J5 阈值);④ oracle 清零(13 例补头 → 真 golden;9 例移 gap/ 或标注"Vitro 扩展")——不改测试预期值,只改驱动与用例头文件 |
本文 §9 的 R-2026-09-01~09 全部先红留痕,修复后转绿;clang_oracle_audit 输出 no_oracle=0 且 vitro_better=0;J5 门禁先用已知泄漏程序证明它会红(先证会红) |
每项独立 PR,可单独 revert | 本阶段只加护栏、不改语义,防线不存在变瞎窗口 |
| P1 防线换代(2~3 周) | ① 步级差分:随机程序 × clang 见证 × 第二实现(Python 语义模型) 三路对照(本次 1000 例已验证可行);② 随机交互序列 + 畸形 JSON fuzz 进夜间;③ 标注/诊断文案 golden(U1#1)+ J3 margin 门禁 | 每个 payload 字段语义 margin ≥3;M2/M6 类突变由"零检出"变"检出"(用当前突变先证新防线会红);J1 100% 方法覆盖 | 探针与门禁全在 scripts/,不合入即回滚 |
新增防线是并列的(不改旧门禁口径),旧防线继续跑 |
| P2 资源与参数域补设计(2~3 周) | ① 交设计文档(窗口/预算/生命周期与参数域)再实现(避免"又一次点修");② 重放窗口化(J5 达标)、regions/output_chunks/trace/vis_event_queue 有界;③ 检查点淘汰悬空 Delta 修复;④ 参数域统一安全转换 |
10 万步 + 随机 seek 序列 RSS ≤64B/步;100 万 malloc/free 线性且 RSS 增量 <32MB;检查点/隔离差分用例全绿;interaction_probe 1000 会话零 panic |
P2 前打 tag;旧引擎二进制保留为参照实现 | 双跑差分:同输入在旧/新引擎跑同一交互序列,逐帧比对 payload;任何差异必须先归因(旧错/新错)再放行,未归因 = CI 黄牌、不发布 |
| P3 常设化 + 结构债(持续) | 随机差分扩到 ≥5000 例 × 多种子 + C++ 生成器;JIT 三路径矩阵;USAGE 台账(J4)建立 | 连续 7 晚零未知差异(或差异全部归档);台账每批更新 | — | — |
7.3 中止条件("何时必须放弃重构")
- P2 连续两轮迭代仍无法把 seek 斜率压到 64B/步,或压缩后核心语义出现 ≥1 条新分歧 → 停止该域重构,退回"显式限制远距 seek"的契约(把做不到的明说成限制,并写入 capabilities/error_catalog),同时重开候选 D 的评估。
- P1 发现"步级 payload 无法定义正确性判据"(即业界/教学组都拿不出独立 oracle) → 停止"以 payload 为重心"的防线换代,退守 J1/J5/J8(参数域、资源、panic)三项可判定的门禁。
- 任何阶段发现 P0 级新事故(GB 级资源事故 / 静默错值扩散到核心语义)→ 立即冻结该阶段, 按事故归档制度留痕后再决定继续或改判。
8. Q6 改判触发条件(对"核心不重写"这条裁定,全部可测量)
本文未采纳"整体重写",因此本节是裁定①的可证伪条件清单。任一条件成立即须重新裁定。
| 编号 | 触发条件(可测量) | 检测方式 | 当前状态 |
|---|---|---|---|
| R1 语义分歧 | 随机三路差分 ≥5000 例 × ≥5 种子出现 ≥1 条语言语义层(lexer/parser/typeck/codegen/vm,非资源/协议/参数域)未记录分歧,可最小复现 | random_diff.py --per-family 500 --seed <多>,差异进已知差异表核对 |
当前 1000 例 × 1 种子零分歧 [动态] |
| R2 margin 崩塌 | 任一核心语义(算术/分支/寻址/调用约定)在所有切面的 margin < 3,且该语义出现 ≥1 条真实错值 | mutation_facet_test.py + 缺陷台账 |
UMod=1、除零=0 已登记;未出现真实错值 |
| R3 使用证据反证 | J4 台账中同一 public 出口 ≥2 次真实失败(学生/下游),且归因均为"缺设计"而非"缺补丁" | J4 台账 × 事故归档 | 台账未建(Q7-G1a/G3)。G1a 改判(2026-09-13)后本条性质不变:被动监听器,证据到达即触发,无需等通道"结案"——首批 2 条现场 4 问题已在行使监听职能(E3053 误报与 code_line 缺口即其捕获) |
| R4 资源复发 | P2 之后同一路径再发生 ≥1 次 GB 级事故 | RSS 门禁 + 事故归档 | 未发生(P2 未开始) |
| R5 结构放大 | C# 引入(CS2/CS3)后 3 个月内,因"单遍 codegen + 固定槽位/多 pass 收敛"结构产生 ≥3 起合法性缺陷(误拒合法代码或静默错值) | CS 批次缺陷台账 | 未发生 |
R1 是最关键的一条:它把"要不要重写核心"从立场之争变成可执行的实验 (成本:一次夜间跑,样本量已写明)。本文据此建议把 R1 作为 U7#1 的验收线, 而不是"连续 7 晚零未知差异"这类无法反驳的软表述。
9. Q7 证据缺口清单(每条含实验、样本量、判据)
允许"证据不足",不允许以"证据不足"结案。以下 8 条是当前无法判定的全部问题。
| 编号 | 无法判定的问题 | 补齐实验 | 样本量/规模 | 判据 | 优先级 |
|---|---|---|---|---|---|
| G1a | 真实学生路径与失败模式——真实通道(T5 的核心)。2026-09-12 更新:已收集 2 条真实现场(用户提供),"输入不存在"不再成立——两条合计暴露 4 个问题(1 个被影子可靠接住 / 1 个已修但形态零覆盖 / 2 个结构性照不到),详见 native/tests/CORE_ASSET_VERDICT_FAILURES.md 的 R-2026-09-12 与 D-2026-09-07。2026-09-13 改判:真实用户短期不可得(下游仅 SharpTutor 且锚定旧二进制,历史试用计划过从未产出),"一次性 ≥30 程序 + ≥300 会话"判据不可执行——改为持续开放通道,不阻塞 CS 系列;R3 为被动监听器,证据到达即触发,不受此改判影响 |
归档入口直接落 native/tests/CORE_ASSET_VERDICT_FAILURES.md(沿用既有 R-/D- 条目格式,不新增文件);SharpTutor 侧匿名真实程序 + 会话轨迹滚动归档 |
时间盒滚动:CS2 交付前或 3 个月,以先到者为准;台账只记累计样本数,不设一次性门槛 | 失败模式复现数 ≥1 已达成(4 个问题);"交互切面命中率 ≥30%" 改为待真实数据回填的开放指标(随样本滚动更新,不得以合成数据代填) | P0(通道建设,随本裁定交付)→ P2(滚动等待,被动) |
| G1b | 防线 6 / U1#1 的靶料缺口——合成通道(G1a 真实输入不可得期间的工程替代)。方法论红线:不得以 MisconceptionPattern 单源自证——六类模式是引擎自产模式空间,用它生成再用防线验证 = 循环论证;实证:2 条真实现场 4 个问题仅 1 个被现有链路接住,真实失败形态已证明超出当前模式空间。合成绿不得表述为"学生失败面已覆盖" | 三源混合:① 外部先验——K&R/OJ 教材常见错误分布(边界差一、= 误写 ==、scanf 漏 &、循环不变量写反等,引擎外知识);② 2 条真实现场的形态扩展家族("按现场形态而非特性清单建语料",§2-T5);③ MisconceptionPattern 六类兜底。每条用例显式标注来源 |
首批三源各 ≥1 族入防线 6,此后随 U1 滚动扩充;合成可无限生成,不设上限 | 每个合成失败模式至少被一条防线接住 + margin 记录;先红后绿(套 J9:上线前先证当前防线接不住);报告口径**"合成覆盖率"与"真实命中率"分列**(沿用 S0 分列纪律) | P0(防线 6 靶料,随 U1 交付) |
| G2 | 步级 payload 的"正确性"判据未定义(当前只能查内部一致性) | P1:第二实现(Python 语义模型)+ clang 见证程序 + 教学组人工审三方对照 | ≥500 程序 × 随机交互序列 | 每个 payload 字段语义 margin ≥3 | P0 |
| G3 | 三出口的真实使用量/使用方式 | 下游埋点 1 个月(会话数/方法分布/错误率);wasm 出口补运行时实测 | 每出口 ≥1 消费者 + ≥100 会话 | J4 台账条目齐备 | P1 |
| G4 | wasm32 的运行时行为(栈溢出/panic/资源)差异 | 用本次 4 个 panic 复现 + 3 个长跑程序跑 wasm 冒烟 | 7 个程序 × wasm 形态 | 零 panic;资源以线性内存峰值替代 RSS | P1 |
| G5 | JIT 与解释器/host 的语义分叉(文档记录但未独立复核) | U5 三路径差分矩阵(opcode/host/JIT × 语义族) | 矩阵单元 100% 覆盖 | 缺测单元 = CI 黄牌;分叉全部进 spec 差异表 | P1 |
| G6 | regions "14B/次无界 / O(N²)" 与本次实测(峰值平坦 8.6MB、耗时≈线性)不一致 |
直接读 regions 条目数(不经 RSS 代理)在 1k/10k/100k/1M 四点采样 | 4 个规模点 × 3 次 | 条目数与耗时增长曲线可复现(任一方向) | P1 → 已关闭(2026-09-14,定论见 §5a:分段饱和模型,两侧既有证据均为真;U2#2 据此解锁) |
| G7 | C++ 面的随机差分完全缺失(本次 10 族全是 C 子集) | 扩随机生成器到类/模板/容器/RAII | ≥500 例 × 5 族 | 零未知分歧或全部归档 | P2 |
| G8 | @category *bug* 自我豁免通道与 vitro_better 的逐例正当性 |
逐例裁定:设计如此(→ 移 gap/ 并写明)还是驱动缺陷(→ 修驱动) |
22 例 + 4 例豁免 | 全部有归属,vitro_better=0 |
P1 |
本次已自行关闭的缺口(留档,避免重复开单):
- "exemption 通道有多大" → 22 例,21 例零比对(§5.1);
- "seek 重放到底多大" → 1.2~2.3KB/步,10M 步外推 12~23GB(§5.3);
- "662 的规模 realism 如何" → 中位 9 行 / 115 步(§T3);
- "核心语义在随机输入下是否稳" → 1000 例三路一致(§1.2-E4)。
10. 红→绿用例清单(CI 必须先留痕 FAIL,再修)
纪律:以下每条在修复前必须先在 CI 产生一条 FAIL 记录(用例编号即本节编号),修复提交
必须引用编号。禁止把它们改成 skip/known_issue,禁止修改任何测试预期值。
本文所有条目在本次会话中均已实测为红(原始输出见对应 JSON)。
| 编号 | 缺陷/要求 | 现状证据(本次实测) | 修复后验收 |
|---|---|---|---|
| R-2026-09-01 | seek 越过程序末尾 → panic |
repro_panics.py A 段:10 步程序 + seek(50000) → exit=101,engine.rs:400 "split index (is 48001) should be <= len (is 10)" |
越界 seek 返回错误帧/success=false,进程存活 |
| R-2026-09-02 | seek 中度越界(同样 panic) |
同 A2:seek(3000) → split index (is 1001) should be <= len (is 10) |
同上 |
| R-2026-09-03 | payload.get 负 end → panic |
B 段:{"start":0,"end":-1} → engine.rs:416 "range end index 18446744073709551615 out of range" |
参数 clamp + 错误帧;进程存活 |
| R-2026-09-04 | serve 主循环无 catch_unwind:一条畸形请求杀死会话 |
interaction_probe.py B 段:30 条输入在第 10 条死亡(仅 9 条响应);cmd_serve 无 panic 护栏 [静态] |
任意畸形行 → 错误帧;≥1000 条 fuzz 输入后进程仍存活 |
| R-2026-09-05 | seek 重放内存斜率超预算(J5) | resource_longrun.py:50k→115.7MB、200k→309.2MB、500k→620.1MB(1.2~2.3KB/步) |
峰值提交/重放步数 ≤ 64B/步(10 万步 ≤6.4MB) |
| R-2026-09-06 | 22 例无外部 oracle 却计入通过(J2) | clang_oracle_audit.py(22)+ oracle_free_classification.py(21 例零比对) |
no_oracle = 0 且 vitro_better = 0 |
| R-2026-09-07 | 驱动对文件用例不注入头文件,13 例本可成为真 golden | oracle_gap_probe.py:13 例补头后 RESCUED_MATCH |
13 例转为有 golden 的普通用例(gap/baseline 归档明确) |
| R-2026-09-08 | 可视化四状态无防线(margin=0) | mutation_facet_test.py M2:Freed→Valid 影子 0 + 测试 0 |
新防线对同一突变 检出 ≥3(先证会红) |
| R-2026-09-09 | 兜底 semantic_label 无防线(margin=0) |
M6:标签恒为"第 1 行",影子 0 + 测试 0(词汇闭包反而通过) | 标注-行为一致性 property 检出 ≥3 |
| R-2026-09-10 | 教学内容/诊断切面 margin=1(低于 3 的门线) | M1(算法标注)、M4(诊断文案)各仅 1 个测试拦截 | 两切面 margin ≥3 |
| R-2026-09-11 | 交互切面整体零 oracle(无 golden 可比) | interaction_probe.py A 段:8/9 会话死于 seek;存活会话仅能查内部一致性 |
P1 建成后:随机交互序列 ≥1000 会话零 panic,且 payload 字段 margin ≥3 |
11. 交付前自检(逐条回答)
- 每条结论标注验证方式了吗?其中多少依赖 AI 编写的用例? 是,全文逐条标注。质量论据不依赖 AI 用例:判"核心稳"用 1000 例随机生成器 + clang + 自写 语义模型(§E4);判"防线强/盲"用突变 margin(§E3)与驱动侧资源测量(§E6)。 AI 编写的 662 用例只在描述现状(覆盖率、oracle 缺失)时被统计,未被当作质量证据。
- 除影子防线外有几个独立验证通道?各照到什么切面?
5 个:① clang 子进程 golden(外部实现而非 AI 用例)→ 语言语义/批处理;② 自写随机程序生成器
- Python 语义模型 → 三路语义差分;③ 突变注入 → 语义可测性与 margin(逐切面); ④ 驱动侧 psapi 资源测量 → 宿主资源;⑤ 随机交互序列 + 畸形 JSON fuzz → 交互出口/参数域。
- 实际测了哪些"想不到的场景"?怎么生成的?
越过程序末尾的
seek(随机交互序列随机命中,非预想);payload.get end=-1(畸形词表);随机交互交错(step/seek/payload/breakpoint/reset); 1000 例随机程序(生成器,含 unsigned/位运算/struct/malloc 链表); 500k 步远距 seek;1M putchar;30 条畸形 JSON。生成方式:随机生成器 + 随机序列 + 突变。 - 交互切面覆盖密度?有使用证据吗? 影子 0/662;工作区 30/810 集成测试(3.7%,其中 8 条只查 schema 形态/词汇闭包), 输入程序为十几个小程序(5 个交互测试文件内联原始字符串 21 处,含 JSON 片段), 对比批处理面 662 个。使用证据:1 个下游消费者(SharpTutor,锚定 10591ad),0 条学生记录, wasm 出口无运行时实测。
- 复现了几条真实学生失败路径?若为 0,为什么?
0 条。原因不是不可复现,而是输入不存在:仓库内无学生实测记录,
学生错误用例集.md是假想清单且无任何测试引用;真实用户试用计划过 (ROADMAP_2026_Q3.mdC2.x 明写"需要真实用户,当前无法由 Agent 独立完成")但从无产物。 → 列为 G1 第一优先,并声明本文不含基于"学生实际行为"的推断。 - 说"债很重/成本很高"时的量化口径是什么? 口径三件套:语义体量(46,516 行 Rust;管线+VM 32,446 行;按历史迁移 8,057 行/4~5 周 外推 ≈6~9 人月)、oracle 条数与规模(640 条 clang golden,中位 9 行/115 步)、 复用损失(22 例不可复用 = 3.3%,25 例需重裁定 = 3.8%)。并且明确:"债"不是主论点—— 主论点是"现有 oracle 不足以验收任何重写"。
- 如果裁定是错的,什么证据会推翻?写成可测量条件了吗? 是,§Q6 R1~R5 全部可测量(R1 已给样本量 ≥5000 例 × ≥5 种子与判据)。特别地, R1 是关于"核心不重写"最关键的反证条件,已建议作为 U7#1 的验收线。
- 重构方案在过渡期会不会让防线变瞎?如何防止? 会——尤其 P2(资源域):新引擎无外部 oracle(clang 不产生 payload/checkpoint 语义)。 防法三条:① P0 仪器先行(护栏与 RSS 门禁在动刀之前在线,并先证会红); ② 旧引擎二进制留作参照实现,同输入双跑逐帧差分;③ 差异未归因不得放行(CI 黄牌), 并明确"参照只保行为、不保正确"——正确性仍须由 P1 的独立 oracle 承担。
12. 状态记录
本节记录本文的历代修订历史。最新执行方案见文末 §13(多轮收敛)—— §13 与 §7 冲突时以 §13 为准;§13 内含其自身的状态记录(§13.7)。
- 2026-09-12:本文立项。基线
master@8236bc5(工作区含文档改动,未提交)。 本次新增 9 个探针脚本与 11 份证据 JSON,落在scripts/core_asset_verdict/。 核心新发现:①seek越过程序末尾 panic(新 P0,不在任何既有清单); ②payload.get负参 panic(既有 R9b,本次独立复现并给最小复现); ③ 662 中 22 例零 oracle(21 例零比对),13 例可补头恢复真 golden; ④ 按切面突变:教学内容 1、诊断 1、可视化 0、兜底标注 0; ⑤ seek 重放斜率 1.2~2.3KB/步(10M 步外推 12~23GB),但为瞬时尖峰而非累积泄漏。 待办:①docs/README.md索引同步(本次已做);②native/tests/*_FAILURES.md台账登记 (见native/tests/CORE_ASSET_VERDICT_FAILURES.md);③CSharp前端引入计划.md§7 需补入本文 §7.3 的中止条件与 §Q6 的 R5 判据。
13. 重构执行方案(多轮收敛,2026-09-12)
本节位置:§6 是候选对比、§7 是 B+C 域内计划、§8 是改判条件。本节把多轮讨论 (独立复核 → 真实学生现场 → oracle 选型 → 工具链语言选型 → 性能实测 → 防线空转发现) 收敛为跨域执行顺序与门禁。与 §7 冲突时以本节为准。 不新增文档:本节就地扩充本文,避免文档数量膨胀带来的管理成本。
13.1 本节依据的新增实测(均可在本仓库复现)
| 证据 | 数值 | 验证 |
|---|---|---|
| 真实学生现场(G1a 首批) | 2 条 → 暴露 4 个问题:① p += 2 误拒 E3045(已修,防线有效:9 用例全有真 golden)② 单条声明混合"不定长数组+标量+指针"被误拒(已修,但形态覆盖 = 0 → D-2026-09-07)③ E3053 char 数组初始化误报 + 未去重(仍存在 → R-2026-09-12)④ 覆盖率 >100%(code_line 跨文件全局行号,仍在) |
[动态实测] |
| serve 出口 P0 | seek(50000) → engine.rs:400 panic(exit 101);payload.get end=-1 → :416 panic;serve 主循环无 catch_unwind |
[动态实测] |
| capi 头文件缺口 | 导出 40 / 声明 23 → 19 个未声明(含 vitro_free_string 与整个 *_json 族)——下游按头文件写代码即 ub |
[动态实测] |
| 影子验证性能 | 缓存全删后冷启动 21.48s、热 1.61s;jobs=16 最优(15.95s)、jobs=8 为 21.48s |
[动态实测] |
| 门禁全流程(CI 12 步) | 49.92s。其中 shadow_cpp 24.75s(占 50%,纯串行)、cargo test 16.57s、three_tier_check 5.43s(重复跑已跑过的测试且 --test-threads=1) |
[动态实测] |
| Python 语言开销上界 | ≈4.1s / 49.92s ≈ 8.2%(热缓存下 shadow 全量为 1.18~1.61s,即 Python 侧全部开销:DLL 加载、663 次 session、ctypes、IPC、比对、报告) | [动态实测+推导] |
| 同构并发加速比 | 78 个 clang++ 编译:串行 12.15s → 线程池 16 路 2.04s(6.0x) |
[动态实测] |
| 其余"十分钟"来源 | replay_s1_s5.py ≥3 分钟未完成(已中止);裁定探针 11 个串行 ≈13.5 分钟(mutation_facet_test 单轮 280s) |
[动态实测+时间戳复原] |
13.2 新增第五域 D1:防线自身(优先于 D2/D3/D4)
理由(本节的中心判断):§0 裁定①"核心不重写"的证据来自防线(随机三路差分、切面 margin)。 若防线自身空转,这组证据必须重新估价——一个不检查的门禁长期全绿,与"真的没问题"在观测上不可区分。
实测到的 7 个"表面正确"实例:
| 脚本 | 声称在做什么 | 实际在做什么 |
|---|---|---|
serve_smoke.py |
出口 3 协议契约,60 条断言 | 只测 happy path(seek {"step":1}、payload.get {0,50} 全用合法值)→ 与 2 个 P0 panic 并存 |
shadow_verify.py |
与 Clang 逐字节对照 | 22 例无 oracle 计入通过,其中 21 例零 stdout 比对 |
| 同上 | 输出比对 | .strip() 比较 → 尾部空白差异永久不可见(tree_level_order 即靠此判 match) |
oracle_gap_probe.py |
测"补头能否救回 golden" | AUGMENT 漏 stdbool.h → "13 例可救"是下界,keyword_compat 被误分类 |
seek_accumulation.py |
测 malloc/free 增长阶 | exponent_estimate: 0.996 的 basis 含 exit=1 未完成样本 |
resource_longrun.py |
验证 U2 验收线"100 万次 malloc/free" | 该点 exit=1 被步数上限截断,却仍作为数据点 |
engineering_health.py |
工程健康门禁 | 只生成报告;CI 注释写明"阈值门禁待固化后启用" → 从未阻塞 |
共同结构:全部"通过",但通过的语义是"脚本自己没崩",而不是"被检查的对象正确"。
根因:引擎侧有突变测试(mutation_facet_test.py,3/3 检出),脚本侧从未做过——防线自己没有防线。
对策(制度化,非一次性):
- 脚本埋雷验证义务(与 §4"保险丝可触发性义务"同构):每个判定型脚本必须至少留有一条 "注入必然违反 → 必须变红"的实证记录,纳入批次验收。
- 优先级:
shadow_verify.py(唯一硬门禁)>ci_three_tier_check.py(失败台账对账核心)serve_smoke.py(已证实空转)。 - 新增判据 J9 脚本可触发性:判定型脚本的埋雷记录 = 0 时,其"全绿"不得作为任何结论的依据。
13.3 五域与执行顺序
| 波次 | 批次 | 域 | 内容 | 依赖 | 规模 |
|---|---|---|---|---|---|
| W0 | W0-1 | D1 | 防线埋雷:serve_smoke(现成雷:2 个 panic)→ ci_three_tier_check → shadow_verify;每处留"注入 → 必须红"记录 |
无 | 小 |
| W0 | W0-2 | D2 | 止血:engine.rs:400 clamp + :416 参数域防御 + serve 主循环 catch_unwind(一条 JSON 不得杀死会话) |
无 | 小 |
| W0 | W0-3 | D2 | capi 契约:vitro_capi.h 补 19 个声明 + 三种所有权书面标注 + 一个 C 侧契约测试(按契约 free 一遍,修复前该测试必须红) |
无 | 小 |
| W0 | W0-4 | D3 | E3053 误报修复(常量初始化器豁免 + 同行同码去重) |
无 | 小 |
| W1 | W1-1 | — | 性能批次(与重构解耦、可并行):shadow_cpp 并发化(-20s)、replay_s1_s5 并发化(≥3 分钟 → 目标 <30s)、--jobs 16、ci_three_tier_check 去重 |
无 | 小-中 |
| W1 | W1-2 | D3 | oracle 建设:C 整数语义金标准表(手算,不由 AI 生成)→ Go 数据表规则 + 启动自检 → 冒泡 3~5 条规则试点 | W0-4 | 中 |
| W1 | W1-3 | D3 | 防线换代:诊断文案 golden、标注-行为一致性 property、oracle 覆盖率清零、切面 margin ≥3 | W1-2 | 中 |
| W2 | W2-1 | D4 | 生命周期补设计:先交设计文档(窗口/预算/生命周期)再实现(重放窗口化;regions/output_chunks/trace/vis_event_queue 有界;检查点淘汰悬空 Delta) |
W0-2 | 大 |
| W2 | W2-2 | D2 | 参数域统一校验(serve/capi 全方法 × 合法域 / 越界 / 极值 / 畸形) | W0-2 | 中 |
| W3 | W3-1 | D5 | 语言迁移:shadow_cpp(Go 试点,同时拿并发)→ replay → 探针集 → 主驱动(双轨对照) |
W1-1、W0-1 | 中-大 |
| W1 | W1-4 | D6 | JIT 加速器存废重裁(2026-09-13 追加,详见 §14.11):先校正 vm_bench(真禁用开关 + 统一入口)重测加速比 → 不显著则删 JIT(执行路径 3→2);显著则收缩作用域(只 JIT 最内层单层循环)。无论走哪条路,J10 必须落地 —— ✅ 已收口(同日):实测 9.16~9.72x → 保留 JIT;作用域收缩由 fast path 修复内建;J10 落地且突变实测 margin=20 |
W0-1 | |
| — | — | — | 不触发:整体重写(§Q4 的 D/E)、换核心语言 | — | — |
顺序的三个理由: ① D1 先于一切——门禁若空转,所有"全绿"依据失效,后续批次会在不可信地基上施工; ② W1-1 与重构解耦——性能批次不触碰引擎语义、收益最大(-20s 起)、风险最低,可与 D1/D2 并行; ③ D5 最后——Go 版脚本同样需要被埋雷验证,先跑通"验证脚本的方法",迁移时才有等价性判据。
13.4 对 U0~U7 的修订(三处数字更正 + 一处新增)
| 项 | 原文 | 实测更正 |
|---|---|---|
| U2 验收线 | "100 万次 malloc/free —— RSS 增量 <1MB 且耗时线性" | 不可执行:实测 400k 次即撞 1000 万步上限(exit=1),1M 次同样未完成。须改为"步数上限内的最大规模"或显式 set_max_steps;且它与共同验收线 #9"规模 realism、禁止缩水"互相冲突,必须二择一 |
| U0#7 capi 头文件 | "补齐 17 个缺失声明" | 实测 19 个(含 vitro_free_string;vitro_compile_json / vitro_run_json / vitro_step_begin / vitro_step_next_json / vitro_get_step_payloads_json / vitro_set_breakpoints / vitro_get_capabilities_json / vitro_set/get_quarantine_budget 等) |
| U7#5 突变抽样常规化 | "每批次抽 3~5 个突变" | 实测单轮 280s(6 突变 ×(release build + 全量 shadow + 全量 cargo test))→ 须先优化(内部 --jobs 16、只跑受影响套件)再常规化,否则每批次固定付 4.7 分钟 |
| 新增 | — | U0 增"脚本埋雷验证"(本方案 D1 / J9) |
13.5 D5 语言迁移的边界与纪律
- 核心保持 Rust 单栈:不换实现语言。依据是双重结论——上一次 C++→Rust 重写解决了内存安全 (编译器强制、无需人盯),但没有解决"缺设计"(Rust 版又泄漏两次,且都是 safe 代码的逻辑无界)。 再做一次整体重写会把 32,446 行语义债重欠一遍,而生命周期缺陷会以同样概率重新长出。
- Python → Go 的动因排序(性能排最后):
① 消除编码类失败模式——全仓库 103 处 UTF-8 样板,且已发生三类实际事故(Windows GBK 炸中文、
\S+正则吞中文注释污染用例名、BOM 干扰 clang 对照); ② 编译器成为跨上下文的纪律执行者——正是"纪律靠上下文维持就会失效"的对策; ③ 表达空间窄——Go 只有一种循环、无继承、错误显式,AI 写不出"反人类但能跑"的代码 (此条优于 C#:C# 表达空间更大,AI 可写出"聪明但难审"的代码); ④ 性能:上界 8.2%(§13.1),不作为动因。 - oracle 用 Go:数据表(JSON,人可审)+ Go 薄解释器 + 启动自检 fail loud(事件类型清单 vs 规则表 key, diff 非空即拒绝启动);规则表是语言无关资产。
- 迁移纪律(不可跳过):主驱动
shadow_verify.py(105KB,承载 E-P1-5 输出通道 / Clang 缓存 key /known_issue双向对账 /@category豁免 /.strip()比对语义 /sorted(glob)确定性分片)必须新旧双轨同跑, 五项结论(663 / match 644 / known_issue 3 / vitro_better 16 / 0 非预期差异)逐项一致才允许切换。
13.6 中止条件(补充 §7.3)
- 埋雷验证发现任一 P0 门禁空转 → 立即冻结所有以"全绿"为依据的结论,先修门禁,暂停其余批次。
shadow_verify的判定逻辑被证明存在系统性空转 → §0 裁定① 与 §5.2 行为债量化均须重新裁定 (它们的证据基础来自该门禁)。- 语言迁移期新旧驱动任一项结论不一致 → 停止切换,差异归因后方可继续。
- U2 验收线规模争议未决(§13.4 第一条)→ 不得开工 D4,因为无法验收。
13.7 状态记录(本节)
- 2026-09-12:本节立项(多轮讨论收敛)。新增第五域 **D1(防线自身)**并置于最前;新增判据 J9; 三处 U 批次数字更正;给出 W0~W3 五域顺序与 D5 迁移纪律。
- 已同步:
docs/README.md索引描述;native/tests/CORE_ASSET_VERDICT_FAILURES.md(R-2026-09-12 / D-2026-09-07 / G1 由"0 条"改为 2 条);docs/spec/STEP_PAYLOAD_SCHEMA_V0_1.md§8 #9(补code_line的消费方可见后果:覆盖率 >100% 与热力图错位,并明确非前端独有)。 - 2026-09-12:D5 W3-1 前两站完成。①
shadow_verify_cpp:Go 版双轨对账一致(94 用例集合 / 逐用例判定 / stdout 内容级)后接管 CI,Clang 并发 16 路 24.75s → 4~5.2s;②replay_s1_s5: Go 版双轨对账一致(61 条断言状态与编号逐行一致,exit 0 / 0.47s 含编译)。W1-1 的 "replay ≥3 分钟未完成"已失效——W0-2 止血(engine.rspanic 修复)后 Python 版实测 0.39s 全绿,性能观察作废;Go 版迁移价值回归 D5 本源(消除编码失败模式 + 编译器纪律)。 两站 Go 版均带 J9 启动自检(--selftest/ 内置断言)与产物新鲜度门禁;Python 版保留为 双轨对照基准。剩余:探针集 → 主驱动shadow_verify.py(须五项指标双轨一致才可切换)。 - 2026-09-12(晚):D5 W3-1 第三站(探针集第一件)完成。
random_diff:Go 版 (scripts/core_asset_verdict/random_diff.go)以 MT19937 + CPython seeding 逐比特复刻 实现"同 seed 同用例集合",与 Python 3.14 双轨对账逐用例一致(1000 例 verdict + expected- clang 输出全同),Go 47.0s / Python 50.7s。三点实证/更正:
① 引擎 DLL 非线程安全实证——Vitro 调用与 clang 并发同池时进程以
0xc0000374(STATUS_HEAP_CORRUPTION)崩死;此前 Python 版未崩只是 6 线程下 vitro 调用碰撞率低, 不是线程安全的证据。Go 版已恢复互斥串行;主驱动shadow_verify.py --jobs的并发 口径存在同源风险,待专项评估(风险记录,非回归)。 ② 基线刷新:库内旧产物(c3159ac)与当前脚本 + 当前 Python 3.14 的运行结果不一致 (历史环境不可复现:可能是旧版生成器或旧 Python),以本次双轨一致结果为新基线; "种子固定可复现"在同环境下由双实现两次运行证实。 ③ 门禁加牙:Python 版main恒return 0(无牙);Go 版非 agree 即 exit 1。 探针集处置口径:防线级/判定型(会再跑)继续迁移;一次性取证(repro_panics / case_census / clang_oracle_audit 等)按 AGENTS.md 判据不迁移,保留 Python 原样。
- clang 输出全同),Go 47.0s / Python 50.7s。三点实证/更正:
① 引擎 DLL 非线程安全实证——Vitro 调用与 clang 并发同池时进程以
- 2026-09-12(晚,续):D5 探针集 interaction_probe 迁移完成,并带来 W0-2 紧迫性的
定量实证。Go 版(整数 seeding 复刻 → 同 seed 同 op 序列)与 Python 版对账逐字段一致。
seed=20260912 实测:9 个随机交互会话中 8 个死于
engine.rs:400seek panic(死亡点 分布 ops=2~102,即任意会话期望几十次交互内必死),恶意输入payload.get end=-1死于engine.rs:416——W0-2 止血批次的两个 P0 在 master 上全部仍然活着。Go 版已按 J9 加牙(死亡/坏帧/不变量违反 → exit 1),当前红;W0-2 修复后转绿即是止血验收。 建议 W0-2 提前执行(小批次:clamp + 参数域防御 + serve catch_unwind)。 - 2026-09-13(续):W0-1 完成 + D5 退役清理。① 三判定型脚本 J9 埋雷
全落地(台账
脚本埋雷验证记录.md):ci_three_tier_check(假 KNOWN 条目 → hard 点名 / exit 1)、serve_smoke(新增边界批;撤 W0-2 钳位埋雷 → 3 FAIL / exit 1——catch_unwind 救活进程时由 id 关联断言层抓语义破坏, 双保险)、shadow_verify(登记 JIT 批次 tpl_add 突变实例)。 J9 顺带抓获脚本自身缺陷两处:serve_smokeresolve_exedebug 优先在 陈旧产物上假绿(已修 mtime 较新者);判定型脚本须从仓库根运行(cwd 敏感)。 ② D5 退役清理:删除 7 个已被 Go 版替代的 Python 驱动 (shadow_verify_cpp / replay_s1_s5 / interaction_probe / random_diff / resource_longrun / seek_accumulation / winmem)——本节前文"Python 版保留 为双轨对照基准"的表述就此修订:D5 六站全部收官、各站双轨一致的 对账记录均已归档在案,基准用途终结,退役删除(git 历史可回取,git show 1d458eb^:scripts/<path>)。CI 活性四件(three_tier / smoke / precompile / engineering_health)与一次性取证/活性生成器保留,分类与 理由见 CHANGELOG Removed 段。删除前后go vet输出逐字节一致(存量 警告非本批引入)。 - 2026-09-13(续):W0-2 / W0-3 / W0-4 全部落地(D6 修复批次之后)。
W0-2 止血收口:① engine.rs 两处 panic 此前"已修复"的判断不成立——
interaction_probe 复跑实证 A 段 8 个会话仍各 panic 一次(
.serve_a_*.err.log全部指向engine.rs:400split_off:seek 远超步数时理论 discard > 缓存长度;:416get_payloads 的((-1).min(cache_end) as usize)负数绕回 usize::MAX—— 旧 clamp 只 min 不封底)。本轮真修(discard.min(len)+ 先钳区间再转 usize)+ serve 主循环catch_unwind(panic → 错误帧 + 保守重建会话;埋雷 验证:注入 panic! 实测错误帧返回、后续请求正常、进程存活);回归锚serve_param_domain_regression.rs五条;探针从红转绿(1800 请求 0 死亡 0 违反、fuzz 存活、stderr 零 panic)。 W0-3 契约止血:capabilities_json 所有权对齐书面契约(红→绿:契约测试 先证两次调用返回同一静态指针);ABI 1.2.0 → 1.3.0;vitro_capi.h补 齐缺失声明(实测 20 个,§13.4 原记 19 再更正;导出 41 = 声明 41 对账)- 三种所有权分区总说明 + clang include 编译验收;capi/mod.rs 22 入口
catch_unwind 全覆盖(22/22);
shared/三个孤儿文件删除。 W0-4(R-2026-09-12):char 初始化器 W3053 误报修复——'A'/char 值域内 整常量豁免(is_char_safe_initializer+char_narrow_suppress)+ 同行同码 去重;9 条误报 → 0,真实截断(超域常量 / 变量赋值 / 赋值语句)仍报警 (typeck_e3053_regression_test四条正反向锚定)+ baseline 用例。 全验收:cargo 66 套件全绿、shadow 667/647/4/16 门禁通过、探针 EXIT=0、 serve_smoke 通过、clippy 零警告。
- 三种所有权分区总说明 + clang include 编译验收;capi/mod.rs 22 入口
catch_unwind 全覆盖(22/22);
- 2026-09-13:D6 / R-2026-09-13 修复批次落地(W1-4 收口)。① fast path
修复(
!is_recording()判断)红→绿闭环:修复前 665/644/output_gap 2/exit 1 → 修复后 666/match 646/门禁通过;②vm_bench.rs方学校正 +jit_enabled结构性 禁用开关(VitroVM公共 API),加速比重测 9.16x(嵌套)/ 9.43~9.72x(单层)/ 0.97x(递归无效形状)——"不赚反亏"撤销,D6 裁定保留 JIT + 作用域收缩 (由修复内建);③ J10 落地:jit_path_parity.rs八条三锚差分 + baselinejit_single_hot_loop.c+ 弱断言升级,突变实测(tpl_add 加→减) margin=20(cargo 11 红 + shadow 9 红),还原后全防线复绿(shadow 666/646 门禁通过 + cargo 63 套件全绿)。附带实证两条:修复前旧 bench 的 "JIT 时间"建立在穿透 bug 的错值执行上(只断言 ret==0 的"表面正确"实例, 已用return sum锚定修复);bTree_default存在 CLI/DLL 入口间 match/FAIL 漂移(模板程序 UB + 堆残留,既有条目已登记,非回归)。 - 2026-09-13:Q7-G1 拆分改判(G1 → G1a + G1b)。动因:真实用户短期不可得(下游仅
SharpTutor 且锚定旧二进制,历史试用计划过从未产出),"≥30 程序 + ≥300 会话"一次性判据
不可执行,而 G1 以 P0 挂起会让人误以为 CS 系列被阻塞。拆为:
G1a 真实通道——归档入口直接落
native/tests/CORE_ASSET_VERDICT_FAILURES.md(不新增文件),时间盒滚动判据(CS2 交付前或 3 个月,先到者为准),"交互切面命中率 ≥30%" 改为待真实数据回填的开放指标(不得以合成数据代填),不阻塞 CS 系列; G1b 合成通道——防线 6 / U1#1 靶料,三源混合(教材/OJ 外部先验错误分布 / 真实现场 形态扩展 / MisconceptionPattern 六类兜底),禁止单源自证(循环论证红线:合成绿 ≠ 真实覆盖——2 条现场 4 问题仅 1 个被现有链路接住,已证明真实形态超出当前模式空间), 判据 = 逐模式拦截 + margin 记录 + 先红后绿(套 J9),"合成覆盖率"与"真实命中率"分列。 R3 性质不变(被动监听,证据到达即触发)。统一整备路线图.md§4 防伪绿机制表与 U1#1 来源列已同步本纪律。
14. JIT trace 路径的 P0 静默错值(2026-09-13 独立复核)
来源:D5 迁移期间的性能/对照核对环节暴露核心资产缺陷 → 本节为独立复核结论 (复现 + 归因修正 + 根因定位 + 双向交叉验证)。 状态:已定位,未修复(本轮只更新文档,不动代码——按用户决定)。 验证方式:以下全部为
[动态实测](本会话实跑,debug 与 release 双构建)。
14.1 现象与最小复现
#include <stdio.h>
int main(){int i,j,inner=0;
for(i=0;i<200;i++){for(j=0;j<200;j++){inner=inner+1;}}
printf("inner=%d i=%d j=%d\n",inner,i,j);return 0;}
| 路径 | 输出 | 判定 |
|---|---|---|
vitro_cli run(executor + JIT) |
inner=20200 i=200 j=0 |
❌ 静默错值(无任何诊断) |
vitro_cli unified(不经 executor JIT) |
inner=40000 i=200 j=200(1085838 步) |
✅ |
| clang | inner=40000 i=200 j=200 |
✅ 基准 |
字节码无罪、unified 执行循环无罪,缺陷在 executor 的 JIT trace 路径。 debug 与 release 构建输出完全相同 → 纯逻辑缺陷,与优化无关(非 ICF/UB)。
14.2 归因修正(重要):与 long long 无关
原始归因为"循环体内写 long long 局部变量",实测不成立:
| 变体 | Vitro | 判定 |
|---|---|---|
原版(long long sum) |
inner=20200 j=0 |
❌ |
| 调换声明顺序 | inner=20200 j=0 |
❌ |
sum 改 int(完全无 long long) |
inner=20200 j=0 |
❌ |
long long 完全不参与循环 |
inner=20200 j=0 |
❌ |
| 最纯粹版(全 int,5 行) | inner=20200 j=0 |
❌ |
按"long long 处理错误"去修会修错方向。
14.3 精确触发条件
三层条件同时满足才触发:
- 外层循环回边计数达到
JIT_THRESHOLD = 100(第 101 轮开始录制); - 内层循环已被 JIT 化(内层 trace 已建立——内层回边计数在第一轮外层内即远超阈值);
- 外层循环体不含条件分支(否则录制
Abort、退回解释、结果正确)。
触发点扫描(内层固定 200):
| 外层次数 | Vitro 输出 | 判定 |
|---|---|---|
| 99 / 100 / 101 | 19800 / 20000 / 20200 | ✅ |
| 102 | 20200(内层恒 0 次、j=0) |
❌ |
| 150 | 20200(同样停住) | ❌ |
14.4 根因
VitroVM::run 的 JIT fast path 在 trace 录制期间仍然生效
(native/crates/vitro_vm/src/core/executor/mod.rs:14-16,未检查 trace_recorder.is_recording())。
事件链:
- 内层循环先被 JIT 化(其 trace 本身正确,见 14.5);
- 外层第 101 轮,
ip_hits[外层头] = 100→recorder.start(外层头); - 录制推进到内层循环头时,fast path 命中内层 trace →
execute_trace_bulk一次跑完整个内层循环,ip 直接落到内层出口; - 录制器从未见到内层循环的任何指令 → 外层 trace =
[外层cond, outer++, j=0, i++, Jump 外层头]; - 外层回边
next_ip == start_ip→RecordResult::Finish(jit_trace.rs:102-104)→ 这条结构不完整的 trace 被编译注册(executor/mod.rs:331-335); - 第 102 轮起每轮外层由 bulk 执行 → 内层被完全跳过。
一组机制解释全部观测:inner = 101×200 + 0(前 101 轮正常、之后内层 0 次)、j 终值
0(j=0 在 trace 内每轮执行,内层循环体不在其中)、触发点第 102 轮、带条件分支的循环体不受影响。
14.5 双向交叉验证(四组实验)
| 实验 | 构造 | 预测 | 实测 |
|---|---|---|---|
| Z / Z2 / Z3 | 外层 50 / 99 / 101(外层不录制)、内层 2000 | 只有内层 trace 生效 → 应正确 | ✅ 全部正确 → 内层 trace 无罪 |
| Y | 内层含函数调用(内层 trace 无法建立) | 外层录制逐条 step → 遇内层回边 Abort → 无外层 trace |
✅ 正确 → 与推荐修复后的行为等价 |
14.6 修复方向(2026-09-13 同日已执行推荐方案)
| 方案 | 改动 | 评价 |
|---|---|---|
| 推荐 | fast path 加 !self.trace_recorder.is_recording() 判断 |
一行;行为等价于已验证正确的实验 Y |
| 备选 | TraceRecorder::record() 遇到"当前 ip 已有 trace"即 Abort |
语义更明确:录制不得跨越已编译 trace |
| 禁止 | 改动内层 trace 逻辑 | Z 系列已证其正确,改动会掩盖真因 |
14.7 为什么门禁全绿却没抓住(防线形状盲区)
覆盖形状恰好互补地漏掉:
| 形状 | 防线表现 |
|---|---|
| 教学用例循环 < 100 次 | 不触发录制 |
| 排序类循环体带条件交换 | 录制 Abort,退回解释 |
| 单层计数循环 | 只有一层,不存在"外层 trace 穿透内层" |
| 嵌套纯计数循环(教科书形态) | 无任何用例覆盖 ← 唯一命中的形状 |
待落为用例(建议 native/tests/cases/baseline/jit_nested_counting_loop.c):14.1 的 5 行程序
+ 一个带 long long 的变体(固化"与 long long 无关"这一事实)。
纪律:先留 FAIL(红)记录,一行修复后转绿(红→绿 + J9)。
14.8 关联:vm_bench 方法学缺陷 —— Phase 25 的加速比从未可信
native/tests/vm_bench.rs 的对照存在两处缺陷:
let result = execute_run(&mut session); // JIT 分支:session_ops 封装
...
vm.jit_traces_mut().clear(); // ① 只清表,不禁用 JIT
let ret2 = vm.run(&mut session2.as_vm_context()); // ② 裸 VM.run,入口根本不同
- ①:
clear()只清空已编译 trace,hits仍会累积并重新触发录制 → "纯解释"轮实际是 混合(前 100 次迭代解释 + 之后 JIT); - ②(更致命):两分支入口不同(
execute_runvsvm.run),同时变了两个变量 →0.66x~0.86x既不能证明 JIT 慢、也不能证明它快。
另:native/benches/vm_benchmark.rs 只测 compile_and_run(编译 + 初始化,checkpoints.save
后即返回),从未执行程序,不是 VM 性能基准。
⇒ "JIT 不赚反亏"的结论必须在校正方法学后重测才能成立(真禁用开关 + 统一入口)。
14.9 对 §13 的影响
| §13 条目 | 本节含义 |
|---|---|
| D1 防线自身 | 又一实证:门禁全绿漏掉教科书式 JIT 目标 → JIT 路径必须有独立用例,不得由"解释器正确"推断 |
| D3 / U5 三路径收敛 | opcode / host / JIT 三路径分叉的新实例,且是静默错值(教学引擎最坏失败模式) |
| 判据 J 系列 | 追加 J10:JIT 生效区间的正确性须有独立覆盖(margin(JIT 路径) ≥ 3);当前该切面未统计 |
| Phase 25 状态 | 由"✅ 完成"降级为 "🚧 有 P0 正确性缺陷 + 性能声明未验证" → 2026-09-13 修复批次后更新:P0 已修复(红→绿闭环)、加速比实测 9.16~9.72x、J10 防线 margin=20——状态回升为"✅ 修复 + 实测",细节见 §14.10/§14.11 |
14.10 状态记录(本节)
- 2026-09-13:本节立项。仅更新文档,未修复代码。
- 2026-09-13(同日,修复批次落地):待办四项全部完成。
① 用例落地(前条已记);② fast path 修复:
executor/mod.rsfast path 加!trace_recorder.is_recording()判断(推荐方案),红→绿闭环——修复前红留痕 665/644/output_gap 2,修复后 665→666 / match 646 / 门禁通过,两条 JIT 用例转绿; ③vm_bench.rs方学校正(真禁用开关jit_enabled+ 统一入口execute_run+ best-of-5 + fail-loud 自检 + 返回码锚定计算值),重测加速比 9.16x~9.7x (嵌套纯计数 9.16x / 单层热循环 9.43~9.72x / 递归无效形状 0.97x 噪声级)—— "0.66x~0.86x 不赚反亏"确认为方法学假象并撤销;④ Phase 25 状态同步 (AGENTS.md:降级记录更新为"已修复 + 加速比实测")与CHANGELOG.md(三条目)。 附带实证:修复后嵌套 1k×1k 撞默认 10M 步上限——修复前内层被穿透跳过、 步数虚低,旧 bench 的"JIT 时间"建立在错值执行上且只断言 ret==0(又一例 "通过 = 脚本自己没崩",已在 bench 中以return sum锚定计算值修复)。
14.11 对重构范围的影响(2026-09-13 追加;同日 D6 裁定收口)
结论:需要扩大——但扩大的是「裁定的覆盖面」与「收敛的优先级」,不是「要重写的代码量」。
14.11.1 裁定①(核心不重写)维持,且被强化
| 事实 | 含义 |
|---|---|
缺陷在 JIT trace 路径(jit_trace.rs / jit_templates.rs / executor fast path) |
属优化层,非 opcode 语义核心 |
unified 引擎(独立执行循环)输出正确 |
字节码 + 解释器语义无罪 |
| 出错的是两条路径的分叉,不是某条路径本身 | 错在关系,不在语义 |
⇒ 出问题的地方恰好不在核心——这是裁定① 的反向证据,核心因此更可信。
14.11.2 新增子域 D6:JIT 加速器(已并入 §13.3 五域表 W1-4)
关键推理:裁定① 的保护范围是"编译管线五段 + VM opcode 语义核心"。JIT 是加速器,不在该范围内 → 不受裁定①保护。而它当前状态:
| 维度 | 状态 |
|---|---|
| 正确性 | P0 静默错值(R-2026-09-13,已定位未修复) |
| 性能收益 | 从未可信(§14.8 两处方法学缺陷) |
| 防线覆盖 | 零(D-2026-09-09) |
| 复杂度 | 第三条执行路径,与 fast path / 录制 / 观测三处交互 |
处置 = 存废重新裁定,而非重写,顺序固定:
① 校正 vm_bench(真禁用开关 + 统一入口)→ 重测真实加速比
② 净收益不显著 → 删 JIT(执行路径 3 → 2,消除一整类静默错值风险)
净收益显著 → 保留但收缩作用域(只 JIT 最内层单层循环)
③ 无论走哪条路 → J10 必须落地
裁定收口(2026-09-13 同日,①②③ 全部执行完毕):
| 步骤 | 结果 |
|---|---|
| ① vm_bench 校正 | 完成:jit_enabled 结构性真禁用开关 + 两分支统一入口 execute_run + best-of-5 + fail-loud 自检(禁用分支断言零 JIT 步、JIT 分支断言加速步 > 0)+ 返回码锚定计算值(return sum,旧版只断言 ret==0——错值程序照样绿) |
| ② 重测加速比 | 净收益显著 → 保留 JIT,作用域收缩:嵌套纯计数 9.16x / 单层热循环 9.43~9.72x / 递归无效形状 0.97x(噪声级)。旧"0.66x~0.86x 不赚反亏"为方法学假象,撤销。作用域收缩已由修复内建实现:录制期禁用 fast path 后,任何含内层循环的 trace 在录制时必然于内层回边 Abort——只有最内层循环能被 JIT 化,无需额外代码 |
| ③ J10 落地 | 完成且超额:jit_path_parity.rs 八条三锚差分(parity + 手算期望值 + 生效性自检)+ baseline jit_single_hot_loop.c(clang golden)+ 弱断言升级(contains→starts_with)。突变实测(tpl_add 加→减):cargo 11 红 + shadow 9 红,margin=20 ≥ 3;未生效形状正确保持绿 |
已知残留(登记,不阻塞):录制期外层每轮重复"start→内层逐条→Abort"的微小开销
(嵌套形状 9.16x 数据证明不痛);可选优化是录制入口预检"体内已有 trace 即不启动",
属性能小项。bTree_default 在 CLI/DLL 两入口间 match/FAIL 漂移——模板程序自身
UB(读未初始化 children,堆残留决定 NULL 与否),E2E_FAILURES 既有条目已登记
"表现非确定性",FAIL 态命中白名单,非回归。
| 方案 | 改动 | 评价 |
|---|---|---|
| A 删 JIT | 删模块 + 清理 fast path | |
| B 收缩作用域(遇嵌套即 Abort) | 录制入口加判定 | 生效中(以等效形式):fast path 修复的 Abort 语义天然实现"只 JIT 最内层" |
| C 只修 fast path | 一行 | 已执行(R-2026-09-13 修复本体);J10 防线兜底已就位 |
与 §13 的 U5 同向:收敛的正确形式不是"让多条路径等价",而是减少路径数与作用域。
14.11.3 D1(防线自身)扩一个维度:形状对抗生成
原 D1 = "脚本埋雷验证"(验证检查器是否会红)。本次暴露的是输入空间维度:
| 内容 | 验证对象 | |
|---|---|---|
| D1a | 脚本埋雷(注入必然违反 → 必须变红) | 检查器本身(判据 J9) |
| D1b | 形状对抗生成:随机控制流形状(循环嵌套深度 / 分支 / 混合),不只随机数据 | 输入空间——本次"嵌套纯计数循环"落在该空间内,首轮即可被抓到 |
D1b 是 U7#1"随机差分"的加强版:随机数据不够,必须随机形状。
14.11.4 U5 提级:J10 前置到 W1
U5(三路径收敛)原排 Wave 3。现有 P0 实证:三路径确实分叉且为静默错值。 ⇒ J10(JIT vs 解释器等价性)前置到 W1,与 oracle 建设同期。理由:CS2/CS3 会大规模扩充 执行语义(ARC、异常展开),每扩一块就多一块分叉面,等 Wave 3 再收为时已晚。
14.11.5 明确不扩大:不重写核心
- 修法是一行(fast path 加
!is_recording()); - 解释器路径正确(
unified1085838 步与 clang 一致)——核心没坏; - 分叉的根源是"存在多条路径且无等价性合同"(设计问题)。重写核心不会消除它——只要仍留 ≥2 条路径,新代码同样会长出分叉;本次缺陷恰恰是在 Rust 重写之后长出来的 (与 §T1"换语言没有换来生命周期设计"同构的教训)。
14.11.6 一句话
范围扩大 3 处(+D6 子域 / D1b 形状对抗 / J10 前置到 W1)、缩小 0 处,但都不是"多写代码", 而是"多裁定一个域 + 多两条防线判据"。裁定①(核心不重写)维持不变。