docs/current/07-质量与裁定/核心资产重构裁定.md
GitHub ↗
当前有效

核心资产重构裁定(独立裁定 v1,2026-09-12)

23876 字·约 60 分钟 阅读 2026-10-10 17:07

现状注记(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 历史 / tag rust-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)
  • 语言面覆盖形状:printf 660、字符串字面量 655、循环 306、指针 295、数组 292, 而 unsigned 仅 26、位运算 23、函数指针 9、union 7、file_io 10、变参 2、math.h 2。
  • 带 .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.md C2.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/ 进重构区")。实测显示同一病理 (边界/参数域从未被设计)跨目录存在:

  1. unified/engine.rs —— 窗口/重放边界(seek 距离无约束、split_off 无防御);
  2. unified/engine.rs + session_api/serve —— 参数域(end=-1、step 越界 → 一条 JSON 杀死会话);
  3. vitro_vm 累积状态 —— regions/trace/output_chunks/vis_event_queue 无预算;
  4. 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_CASES 2 + @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%)。 行为债的真实主体不是"用例失效",而是两件事:

  1. 语义体量: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++/模板/容器面比当年更大;
  2. oracle 的窄带:640 条 golden 的中位规模是 9 行 / 115 步, unsigned 只覆盖 26 例、函数指针 9 例、union 7 例、file_io 10 例—— 重写即使 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 与评估报告两侧既有证据均为真(观测区间不同):

  1. 推进期(条目 < 隔离预算 ÷ 块大小):条目随 N 线性增长——评估报告的 "14B/次"(条目 MemoryRegionData 的字节成本)在此段成立;每次操作扫描条目数 随 N 涨,时间含 O(N²) 分量——P-1 的"×5 规模 ×10 时间"跨段观测成立;
  2. 饱和期(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. 饱和机制是设计内行为(隔离区决议 §3 的 FIFO + 预算驱逐),非静默丢条目 ——复用路径的 is_freed 复位 + freed_logs retain 清理保持 UAF 检测窗口 语义完好(memory.rs 复用分支亲读确认);
  4. 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 边界与接口冻结策略

  1. 先冻结"被消费的语义",再动结构:spec/STEP_PAYLOAD_SCHEMA_V0_1.md 已冻结字段集; 本次补冻参数域契约(每个 serve/capi 方法的合法域与越界响应),作为 J1 的判定依据。
  2. checkpoint/snapshot 的 wire 语义当前未进 schema —— C 阶段若需变更,必须先走 schema 版本化(v0.2 激活轨道已在 unified/contracts.rs + 冻结测试里,复用该机制)。
  3. 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 中止条件("何时必须放弃重构")

  1. P2 连续两轮迭代仍无法把 seek 斜率压到 64B/步,或压缩后核心语义出现 ≥1 条新分歧 → 停止该域重构,退回"显式限制远距 seek"的契约(把做不到的明说成限制,并写入 capabilities/error_catalog),同时重开候选 D 的评估。
  2. P1 发现"步级 payload 无法定义正确性判据"(即业界/教学组都拿不出独立 oracle) → 停止"以 payload 为重心"的防线换代,退守 J1/J5/J8(参数域、资源、panic)三项可判定的门禁。
  3. 任何阶段发现 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. 交付前自检(逐条回答)

  1. 每条结论标注验证方式了吗?其中多少依赖 AI 编写的用例? 是,全文逐条标注。质量论据不依赖 AI 用例:判"核心稳"用 1000 例随机生成器 + clang + 自写 语义模型(§E4);判"防线强/盲"用突变 margin(§E3)与驱动侧资源测量(§E6)。 AI 编写的 662 用例只在描述现状(覆盖率、oracle 缺失)时被统计,未被当作质量证据。
  2. 除影子防线外有几个独立验证通道?各照到什么切面? 5 个:① clang 子进程 golden(外部实现而非 AI 用例)→ 语言语义/批处理;② 自写随机程序生成器
    • Python 语义模型 → 三路语义差分;③ 突变注入 → 语义可测性与 margin(逐切面); ④ 驱动侧 psapi 资源测量 → 宿主资源;⑤ 随机交互序列 + 畸形 JSON fuzz → 交互出口/参数域。
  3. 实际测了哪些"想不到的场景"?怎么生成的? 越过程序末尾的 seek(随机交互序列随机命中,非预想); payload.get end=-1(畸形词表);随机交互交错(step/seek/payload/breakpoint/reset); 1000 例随机程序(生成器,含 unsigned/位运算/struct/malloc 链表); 500k 步远距 seek;1M putchar;30 条畸形 JSON。生成方式:随机生成器 + 随机序列 + 突变。
  4. 交互切面覆盖密度?有使用证据吗? 影子 0/662;工作区 30/810 集成测试(3.7%,其中 8 条只查 schema 形态/词汇闭包), 输入程序为十几个小程序(5 个交互测试文件内联原始字符串 21 处,含 JSON 片段), 对比批处理面 662 个。使用证据:1 个下游消费者(SharpTutor,锚定 10591ad),0 条学生记录, wasm 出口无运行时实测。
  5. 复现了几条真实学生失败路径?若为 0,为什么? 0 条。原因不是不可复现,而是输入不存在:仓库内无学生实测记录, 学生错误用例集.md 是假想清单且无任何测试引用;真实用户试用计划过 (ROADMAP_2026_Q3.md C2.x 明写"需要真实用户,当前无法由 Agent 独立完成")但从无产物。 → 列为 G1 第一优先,并声明本文不含基于"学生实际行为"的推断。
  6. 说"债很重/成本很高"时的量化口径是什么? 口径三件套:语义体量(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 不足以验收任何重写"。
  7. 如果裁定是错的,什么证据会推翻?写成可测量条件了吗? 是,§Q6 R1~R5 全部可测量(R1 已给样本量 ≥5000 例 × ≥5 种子与判据)。特别地, R1 是关于"核心不重写"最关键的反证条件,已建议作为 U7#1 的验收线。
  8. 重构方案在过渡期会不会让防线变瞎?如何防止? 会——尤其 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 检出),脚本侧从未做过——防线自己没有防线。

对策(制度化,非一次性):

  1. 脚本埋雷验证义务(与 §4"保险丝可触发性义务"同构):每个判定型脚本必须至少留有一条 "注入必然违反 → 必须变红"的实证记录,纳入批次验收。
  2. 优先级:shadow_verify.py(唯一硬门禁)> ci_three_tier_check.py(失败台账对账核心)

    serve_smoke.py(已证实空转)。

  3. 新增判据 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)

  1. 埋雷验证发现任一 P0 门禁空转 → 立即冻结所有以"全绿"为依据的结论,先修门禁,暂停其余批次。
  2. shadow_verify 的判定逻辑被证明存在系统性空转 → §0 裁定① 与 §5.2 行为债量化均须重新裁定 (它们的证据基础来自该门禁)。
  3. 语言迁移期新旧驱动任一项结论不一致 → 停止切换,差异归因后方可继续。
  4. 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.rs panic 修复)后 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 原样。
  • 2026-09-12(晚,续):D5 探针集 interaction_probe 迁移完成,并带来 W0-2 紧迫性的 定量实证。Go 版(整数 seeding 复刻 → 同 seed 同 op 序列)与 Python 版对账逐字段一致。 seed=20260912 实测:9 个随机交互会话中 8 个死于 engine.rs:400 seek 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_smoke resolve_exe debug 优先在 陈旧产物上假绿(已修 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:400 split_off:seek 远超步数时理论 discard > 缓存长度; :416 get_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 零警告。
  • 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 八条三锚差分 + baseline jit_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 精确触发条件

三层条件同时满足才触发:

  1. 外层循环回边计数达到 JIT_THRESHOLD = 100(第 101 轮开始录制);
  2. 内层循环已被 JIT 化(内层 trace 已建立——内层回边计数在第一轮外层内即远超阈值);
  3. 外层循环体不含条件分支(否则录制 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())。

事件链:

  1. 内层循环先被 JIT 化(其 trace 本身正确,见 14.5);
  2. 外层第 101 轮,ip_hits[外层头] = 100 → recorder.start(外层头);
  3. 录制推进到内层循环头时,fast path 命中内层 trace → execute_trace_bulk 一次跑完整个内层循环,ip 直接落到内层出口;
  4. 录制器从未见到内层循环的任何指令 → 外层 trace = [外层cond, outer++, j=0, i++, Jump 外层头];
  5. 外层回边 next_ip == start_ip → RecordResult::Finish(jit_trace.rs:102-104)→ 这条结构不完整的 trace 被编译注册(executor/mod.rs:331-335);
  6. 第 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_run vs vm.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.rs fast 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 失去(尚未验证的)收益 已否决:实测 9x+ 收益真实且显著
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 明确不扩大:不重写核心

  1. 修法是一行(fast path 加 !is_recording());
  2. 解释器路径正确(unified 1085838 步与 clang 一致)——核心没坏;
  3. 分叉的根源是"存在多条路径且无等价性合同"(设计问题)。重写核心不会消除它——只要仍留 ≥2 条路径,新代码同样会长出分叉;本次缺陷恰恰是在 Rust 重写之后长出来的 (与 §T1"换语言没有换来生命周期设计"同构的教训)。

14.11.6 一句话

范围扩大 3 处(+D6 子域 / D1b 形状对抗 / J10 前置到 W1)、缩小 0 处,但都不是"多写代码", 而是"多裁定一个域 + 多两条防线判据"。裁定①(核心不重写)维持不变。