本文档面向模板维护者,定义模板目录结构、占位符语法、生成用例防线及未来改进方向。模板的展示形态(模板栏、参数对话框、教程面板、可视化组件)已随 2026-09-11 前端切割移交社区前端,本文档只描述本仓库(纯后端)可维护的部分。
最后核对日期:2026-10-07(删区批现役化——§4 生成链路改「存量产物态」〔sync_templates.py 已随删区退役、82 生成用例迁 corpus/template_generated 不可自动重生成〕、§5.2 出口表换统一入口现役版、§5.3 影子验证/Rust E2E 改退役注记 + clang_direct 承接;anchor 现状与 §6 历史记录不变。前一沿革 2026-09-29 anchor 现状与 S8 契约节新增)
历史修订:2026-09-11(移除
CideFlutter/、index.json、Dart 测试相关引用)
1. 目录结构
每个模板位于 templates/<key>/ 目录下:
templates/
<key>/
meta.yaml # 模板元数据
source.c # C 模板源码(二选一)
source.cpp # C++ 模板源码(二选一)
source.c 与 source.cpp 只能存在一个。scripts/sync_templates.py(已退役)(R4 G1 恢复版)会扫描模板目录并按扩展名渲染;历史版本的 index.json 产物已随 2026-09-11 前端切割移除、不再生成。维护者仍应人工遵守该约定(见 §4)。
实测(2026-09-11):
templates/下 88 个模板目录 = 82 个source.c+ 6 个source.cpp;native/tests/cases_template_generated/下 83 个文件 = 82 个.c+ 1 个E2E_FAILURES.md。
2. meta.yaml 字段
key: bubble # 目录名,必须唯一
name: 冒泡排序 # 展示名称
category: 排序 # 分类,用于分组展示
params: # 参数定义(可选)
n:
label: 数组长度
type: int # int | string | identifier
default: 5 # 默认值,用于 shadow 用例生成
tutorial: # 教程步骤(可选)
steps:
- title: 外层循环
description: 控制排序轮数
anchor: outer_loop # 对应源码中的 // @tutorial-anchor: outer_loop
knowledge_nodes: # 关联知识图谱节点(可选)
- Algorithm
- Sorting
anchor 现状与 S8 契约(2026-09-29 拍板,as_of 当日实测)
- 现状(诚实披露):88 个 meta.yaml 的 95 个
anchor值全部为中文描述(如 「红黑树性质」),源码中@tutorial-anchor标记出现 0 次——按上表 schema 语义全量失配;params有内容的文件数 0/88。此前sync_templates.py的 Dart 硬编码教程读取(前端切割后恒空)已于 2026-09-29 作为死代码删除。 - S8 契约拍板(用户裁定:先闸后铺):教学步骤生成器契约定型时,先落
最小 schema 校验闸(anchor 匹配数纳入机判,禁静默 default——当前全失配
事实须显式红/白名单化),再按生成器实际需要的锚点粒度半自动铺
@tutorial-anchor标记;不在契约定型前预铺(避免锚点粒度返工)。
3. 占位符语法
模板参数在源码中以合法 C 注释形式出现,便于默认状态下直接被 Clang/Vitro 编译:
int arr[/*__PARAM_n__*/ 5] = {1, 2, 3, 4, 5};
int n = /*__PARAM_n__*/ 5;
/*__PARAM_<key>__*/为占位符标记。- 占位符后的第一个非空标记为默认值。
- 当前支持的默认值字符集:
[^\s\[\]();,]+,可覆盖数组大小、变量初始化、函数参数等场景。
4. 生成用例链路(2026-10-07 删区后现状)
4.1 链路现状(自动生成段已断——存量产物态)
templates/<key>/source.c 模板源(合法 C,人类维护)
↓ ✂ sync_templates.py 已随 2026-10-05 删区退役(R4 G1 恢复版的生成链路终止;
↓ 原 native/tests/{cases_template_generated,cases_golden}/ 已物理删除)
corpus/template_generated/<key>_default.c 82 个 .c = **存量产物**(随删区迁入 corpus/,
生成器删除后不可再自动重生成——改模板须人工同步或恢复生成器,
与 #40〔templates meta.yaml 孤儿处置〕联动)
↓
└─ clang_direct 直拍门禁(现役):corpus/template_generated 在其六目录语料域内
(scripts/clang_direct/main.go),Clang 实跑产 golden 逐例对照;
go run ./scripts/clang_direct
4.2 生成器终局:sync_templates.py 已随删区退役
- 2026-09-12 ~ 2026-10-05:R4 G1 曾自历史提交恢复
sync_templates.py为纯后端形态(扫描 templates/ → 渲染占位符 → Clang 产 golden);2026-10-05 S9 工序④随 Python 残留清理整体删除(对象 = Rust 区配套防线,防线本体已由 clang_direct 吸收)。生成能力如需恢复属新立项(与 #40 三选一处置联动:删 / 并入课程体系 / 封存登记)。 - 原第 4/5 步(
CideFlutter/assets/templates/index.json、Flutter assets 拷贝)已随前端切割(2026-09-11)永久移除。 - 静态一致性校验脚本
scripts/test_templates.py自前端切割起即不在仓库中(历史资产,已迁出——反例语境,非失效指引),模板目录完整性核对仍依赖人工(见 §5.1)。
4.3 人工核对流程(test_templates.py 恢复前的临时约定)
- 修改
templates/<key>/source.c(或source.cpp)与meta.yaml。 - 直接用 Clang 编译运行模板源确认合法、输出稳定(模板本身即合法 C/C++,这是本设计的关键红利)。
- 人工同步
corpus/template_generated/<key>_default.c(生成器已删,不可自动重生成):用默认参数替换/*__PARAM_x__*/占位符,并在首行补// @category: ...标记。 - 完整义务链(clang golden → e2e → 直拍 → facts)见 Agent Skill vitro-baseline-corpus-workflow;模板生成用例的 golden 由 clang_direct 运行期实产(不入库)。
- 跑
go run ./scripts/clang_direct确认无新增非预期差异(原 Shadow/Rust E2E 双防线已随删区退役,见 §5.3)。
5. 测试防线
5.1 静态一致性核对(当前无自动化脚本)
原命令 python scripts/test_templates.py 已失效(脚本已随前端切割删除,不在仓库中,且未随 R4 G1 恢复;历史资产,已迁出)。恢复前只能人工核对下列条目:
- 每个模板目录包含
meta.yaml和source.c/source.cpp之一。(2026-09-11 实测:88 个目录、88 个meta.yaml,此项无缺) meta.yaml中key/name/category存在且key与目录名一致。meta.yaml中声明的 params 与源码中的占位符一一对应(⚠️ 2026-09-11 实测:现存 88 个模板的params:全部为空,而占位符仍散落在source.c中——即这条校验在当前数据上已失去约束力,须逐个人工比对)。- 每个 param 都有
default值。 native/tests/cases_template_generated/<key>_default.c与模板源保持同步(改模板后运行python scripts/sync_templates.py(已退役)自动重新生成;一致性人工抽查)。native/tests/cases_golden/<key>_default.out与生成用例一一对应。
缺口记录:以上核对在切割前由
sync_templates.py+test_templates.py自动保证;前者已由 R4 G1 恢复(2026-09-12),后者仍缺、依赖人工纪律。这是已知缺口,不是"已完成"状态。
5.2 出口冒烟(替代原 Dart 单元/Widget 测试)
原 Dart 测试(flutter test test/models/template_loader_test.dart、test/widgets/template_bar_test.dart、test/widgets/ide_template_bar_test.dart、test/providers/ide_notifier_test.dart,历史资产,已迁出)已随前端切割整体移出仓库(CideFlutter/ 见标签 before-frontend-split)。模板相关行为现在只能通过三个后端出口验证:
| 出口 | 验证方式(2026-10-07 现役) |
|---|---|
| 统一入口 CLI | scripts/bin/vitro run corpus/template_generated/<key>_default.c(或 step / api;native/wasm 双臂同形) |
| wasm-gc | demo 单页(demo/)现场消费 gateway wasm.wasm;CI demo_smoke 冒烟 |
| serve | JSON-lines 会话帧冒烟:go run ./scripts/serve_smoke(原 vitro_cli serve 已随删区退役) |
原 Dart 测试覆盖的语义点(模板加载、ext 字段、占位符替换、教程模式下切 main.c/main.cpp)现在属于社区前端职责,本仓库不再提供对应测试。
5.3 影子验证与 Rust E2E(均已随 2026-10-05 删区退役)
模板生成用例的对拍防线由 clang_direct 直拍门禁整体吸收(删区批语料域差量 0——见《Clang直拍门禁》):
- 现役驱动:
go run ./scripts/clang_direct(corpus 六目录全量,含corpus/template_generated/;Golden 来自 Clang 实时输出〔不能来自 Vitro 自己〕的设计原则不变;known 白名单scripts/clang_direct/known_direct.jsondigest 锁定) - 原驱动(历史口径,tag
rust-oracle-freeze):scripts/shadow_verify(Go)与native/tests/vitro_e2e.rs(KNOWN_TEMPLATE_FAILURES双向登记机制随之终结;corpus/template_generated/E2E_FAILURES.md台账存量保留)
6. 历史修复记录(6.1~6.3 已归档,6.4 仍有效)
归档说明(2026-09-11):§6.1~§6.3 记录的是已被移出仓库的前端代码(
CideFlutter/下的TemplateLoader、IdeState、ide_screen.dart、ExecutionControlPanel)的缺陷与修复过程,作为历史资产保留在本文档,不再具备可执行性;相关代码见标签before-frontend-split。§6.4 记录的是模板源自身的缺陷,与前端无关,仍然有效。
6.1 C++ 模板无法加载(历史归档 · 前端已迁出)
现象:CideFlutter/assets/templates/ 中存在 cpp_*.cpp,但 TemplateLoader.load() 只尝试加载 .c,导致 C++ 模板被静默跳过。
修复:
TemplateLoader读取index.json的ext字段,加载.c或.cpp。CodeTemplate增加ext字段。completeTutorial根据ext将当前文件切换为main.c或main.cpp,确保 Rust 后端按正确语言模式编译。
6.2 教程无法退出 / 运行状态混乱(历史归档 · 前端已迁出)
现象:点击模板进入教程后,点击“跳过”或“运行代码”,底部教程面板理论上应消失,但顶部的 ExecutionControlPanel 仍显示上一段运行的进度条/覆盖率,造成“还在模板里”的错觉。
根因:
IdeState.copyWith无法通过activeTutorial: null清除教程状态(被?? this.activeTutorial覆盖)。- 教程模式下未隐藏
ExecutionControlPanel,上一段运行的残留状态会与新界面叠加。
修复:
IdeState.copyWith增加clearActiveTutorial标志。completeTutorial使用clearActiveTutorial: true正确退出教程。ide_screen.dart在activeTutorial != null时隐藏ExecutionControlPanel。(上述 Dart 文件均为历史资产,已迁出)
6.3 覆盖率显示超过 100%(历史归档 · 后端修复部分仍有效)
本条前半段的前端绕过逻辑(
ExecutionControlPanel)已随前端迁出;后半段的后端修复(SourceLoc.file_id过滤 heatmap 行号)仍在仓库中生效,是本条最有价值的部分。 现象:执行控制面板显示“覆盖率 633.3%”。
根因:VM 执行热力图会记录标准库/预编译字节码的行号,导致 lineCounts 中出现远超当前源码行号的条目。
修复:
- 给
vitro_shared::SourceLoc增加file_id: i32字段(0 表示用户主文件,非 0 表示外部文件/标准库),旧产物通过#[serde(default)]保持兼容。 - Bytecode Libc 加载器 (
vitro_vm::bytecode_libc_loader) 在加载预编译产物后,将所有 libc 指令的loc.file_id置为 1。 - VM 执行器 (
vitro_vm::core::executor) 记录 heatmap 时只统计file_id == 0且line > 0的指令,从源头避免外部行号混入。 ExecutionControlPanel._buildCoverageText移除前端按totalLines过滤的绕过逻辑,heatmap 数据本身已只包含用户源码行号。
诚实记录:SourceLoc 字面量构造点众多(Parser/CodeGen/测试等),本次通过批量脚本补全 file_id: 0 完成迁移;后续新增构造应优先使用 SourceLoc::new(line, column) 或 SourceLoc::with_file(line, column, file_id)。
6.4 模板源码自身缺陷
| 模板 | 问题 | 修复 |
|---|---|---|
factorial |
meta.yaml 声明 n 参数,但 source.c 未使用占位符 |
在 factorial() 调用处加入 /*__PARAM_n__*/ 5 |
fib |
同上 | 在 fibonacci() 调用处加入 /*__PARAM_n__*/ 7 |
merge |
merge() 函数定义在 mergeSort() 之后,Clang 报隐式声明 |
调整函数顺序 |
threadedBinaryTree |
线索化遍历缺少终止条件,导致无限循环 | 引入标准头节点法遍历 |
7. 未来改进规划
7.1 模板提示增强(P1 · 已移交社区前端)
以下三项均属社区前端职责,本仓库不再实现;后端只保证模板目录结构、
meta.yaml与占位符语法稳定可用。
- 参数输入提示:在
TemplateParam中增加hint字段,参数对话框展示填写示例与取值范围。 - 模板选择提示:模板栏(
TemplateBar)支持长按/悬停显示模板简短说明。 - 搜索与分类:模板数量增加后,增加分类下拉与关键字搜索。
7.2 占位符能力扩展(P2)
- 支持多行默认值(如初始化列表
/*__PARAM_arr__*/ {1,2,3})。 - 支持同一参数在源码中出现多次(当前已支持,正则会全部替换)。
- 支持条件占位符,如
/*__PARAM_lang__==cpp*/ ... /*__PARAM_END__*/。
7.3 教程系统升级(P2 · 已移交社区前端)
教程渲染(步骤高亮、变量提示、面板切换)属社区前端职责。本仓库只负责在协议载荷中提供语义标注字段(见
docs/spec/STEP_PAYLOAD_SCHEMA_V0_1.md的semantic_label/algorithm_step)。
meta.yaml支持explanations完整写入,不再依赖前端硬编码。- 教程步骤支持高亮多行与变量提示。
- 教程结束时自动展示运行输出,避免学生看不到运行结果。
7.4 后端热图过滤(P3 · ✅ 已完成后端部分)
- 后端已完成:
vitro_shared::SourceLoc的file_id字段 + Bytecode Libc 加载器把 libc 指令标记为外部文件 + VM 记录 heatmap 时只统计file_id == 0 && line > 0(见 §6.3)。 - 协议侧口径:
docs/spec/STEP_PAYLOAD_SCHEMA_V0_1.md的heatmap_line/heatmap_count已是纯用户源码行号,消费方不需要再自行过滤。
8. 相关命令速查
# 防线 1:Shadow Verification(含模板生成用例,Golden 来自 Clang)
go run ./scripts/shadow_verify
# Rust E2E:模板用例对 cases_golden/*.out 断言(工作目录 native/)
cd native && cargo test --test vitro_e2e
# 单条模板用例人工冒烟(三出口之一:CLI)
cd native && cargo run --release --bin vitro_cli -- run tests/cases_template_generated/<key>_default.c
# serve 出口冒烟
go run ./scripts/serve_smoke
# ⚠️ 以下历史命令已失效(脚本随前端切割删除,历史资产,已迁出):
# python scripts/test_templates.py # 校验模板静态一致性(R4 G1 未恢复,仍缺)
# cd CideFlutter && flutter test ... # Dart 单元/Widget 测试
模板维护流程:改模板后运行
python scripts/sync_templates.py(已退役)重新生成用例与 Golden(R4 G1 恢复版);静态一致性人工核对见 §5.1。