- 状态:已实现(v0 baseline)
- 日期:2026-06-15
- 决策者:项目所有者 @HeDaas-Code(owner 拍板 4 条偏差接受)
- 范围:v0 基础版引擎(v0-issue-1 ~ v0-issue-19)
- HITL 性质:本 ADR-0002 本应是 owner 亲手完成。但 owner 在 2026-06-15 明确指示"帮我把两个需要 HAL 的 iss 做了"——本 ADR 由 Hermes agent 代写登记,owner 应在事后审查所有"接受"决策,如有异议可推翻修订。
ADR-0001(docs/adr/0001-v0-baseline-script-spec.md)是 v0 脚本规范。
v0-issue-1 ~ v0-issue-19 按 ADR-0001 实施完成(19 个 feat commit,HEAD = 9f0ea8d)。
实施过程中发现4 处与 ADR-0001 不一致——按 docs/agents/domain.md "ADR 冲突提示"约定,必须显式登记到本 ADR-0002,而非静默覆盖。
- ADR-0001(
docs/adr/0001-v0-baseline-script-spec.md)—— 规范源 - PRD-0001(
docs/prds/0001-v0-engine-implementation.md)—— 实施要求 - v0-issue-20 审计(
docs/audit/v0-invariant-audit.md)—— 不变量守护结果 - wiki 偏差页(
工作Wiki/30-protocol/implementation-deviations.md)—— 详细分析
| v0-issue | GH # | commit | 标题 |
|---|---|---|---|
| v0-issue-1 | #23 | 08784cc |
仓库骨架 + 包结构 + pytest 配置 |
| v0-issue-2 | #24 | 9ff1602 |
AST 节点 dataclass + 错误类 |
| v0-issue-3 | #25 | 03fdb81 |
命令 schema dataclass(GUI→Engine 3 条) |
| v0-issue-4 | #26 | 9995247 |
事件 schema dataclass(Engine→GUI 6 条) |
| v0-issue-5 | #27 | 98ff479 |
双向 EngineBus 封装(multiprocessing.Queue + JSON 序列化) |
| v0-issue-6 | #28 | 427567a |
neon 围栏块拆分器 |
| v0-issue-7 | #29 | dafb110 |
块级骨架解析 |
| v0-issue-8 | #30 | 3930f7a |
元数据区解析 |
| v0-issue-9 | #31 | e242f31 |
next 声明解析 + 归一化 |
| v0-issue-10 | #32 | cdaa634 |
块内语句解析 |
| v0-issue-11 | #33 | 430623b |
node if 解析 |
| v0-issue-12 | #34 | 17eb1b1 |
@xxx 修饰器行解析 |
| v0-issue-13 | #36 | c9d0fe1 |
GameState + Executor 骨架 |
| v0-issue-14 | #37 | 7ff4312 |
核心节点执行 |
| v0-issue-15 | #38 | af90762 |
@style 修饰器执行 + 块级作用域 |
| v0-issue-16 | #39 | abb67ab |
node if 打桩执行 + 跨块 ID 校验 |
| v0-issue-17 | #40 | 12c2c6c |
core 进程入口 main.py |
| v0-issue-18 | #41 | 33a51ad |
runtime GUI 占位(仅路径 B) |
| v0-issue-19 | #42 | 1a76382 |
chapter01 fixture + 端到端集成测试 |
新增验收 commit(v0-issue-20/21 HITL):
9f0ea8dfeat(wiki): CodeGraph 接入 + 4 条覆盖盲点本 ADR-0002 commitdocs: v0-issue-20/21 HITL 验收 + ADR-0002 + audit 报告
| ADR 维度 | 状态 | 证据 |
|---|---|---|
| §8 MVP 表 18 条 | ✅ 18/18 实现 | tests/test_mvp_table.py(19 个用例含 e2e) |
| §11 关键不变量 10 条 | ✅ 10/10 守护 | tests/test_invariants.py(11 个用例含 grep) |
| v0 唯一跑通路径 | ✅ 端到端跑通 | tests/integration/test_echo_path.py |
| 3 条 grep 守护 | ✅ 全部 0 命中 | docs/audit/v0-invariant-audit.md §3 |
| pytest 全绿 | ✅ 182/182 | python -m pytest tests/ -q |
- ADR-0001 §4.1 表述:"块级作用域不跨块继承"
- §11 不变量 #2:"块级作用域不跨块继承"
- ADR-0001 §4.1 未明确"何时清空"——只说"不跨块"
- v0-issue-15 工程笔记原文:"v0 在
run_block开头清,不是在End时清;实施 agent 拍板" - 实际实现:
executor.py:459self._deco_state.clear()在run_block入口(node start 之后立即) - 决策:✅ owner 接受——进入时清比结束时清更稳妥(避免一个块末尾的修饰器被下一块继承)。后续 ADR 修订应把"清空时机"明确为"块入口处"。
- ADR-0001 + v0-issue-2 工程笔记:
Branch.target: NextDecl | Echo | In(用 AST 节点做 union) - 实际实现(
ast_nodes.py:97):新增CallExpression(kind: str, var: str)(kind="echo"|"in"),Branch.target: NextDecl | CallExpression - 决策:✅ owner 接受——两者语义等价(都把 echo/in 简写折成可识别 token)。
CallExpression是 v0 阶段合理简化(避免和In/Echo节点语义混淆——echo/in 在分支项里是调用语义,与块内的 In/Echo 节点执行不同)。后续 ADR 修订可正式登记此新类型。
- v0-issue-2 工程笔记:
ParserError(SyntaxError)带loc: BlockLocation(必填) - 实际实现(
ast_nodes.py:202-207):ParserError(message, loc: BlockLocation | None = None)—— 可选 - 决策:✅ owner 接受——实现放宽约束(容错更友好)。所有现有调用方都传
loc,但加默认值None让测试 / 异常路径构造更灵活。后续 ADR 修订可放宽 spec。
- v0-issue-17 工程笔记:"主循环:1. Executor.run() 启动... 3. 收到 ShutdownCmd → 退出 0... GUI 不可用时降级到 headless"
- 实际实现(
main.py:67):直接加载 CLI arg 的 chapter_path + run,不监听 cmd_q - 决策:✅ owner 接受——v0 简化:LoadChapterCmd / ShutdownCmd 在 v0 阶段仅是 schema 文档,不参与主循环(路径 B GUI 不主动发这些 cmd)。v1+ 加 GUI 主动发 LoadChapterCmd 时再启用读 cmd_q 路径。LoadChapterCmd 当前被
test_engine_bus.py等协议层测试覆盖。
通过 CodeGraph codegraph_explore 自动检测到 4 个 internal helper 无直接单元测试:
| GAP | 符号 | 位置 | 间接覆盖 | 决策 |
|---|---|---|---|---|
| GAP-1 | _drain / _close_queue |
bus.py:63, 74 |
test_engine_bus.py 走 close() 路径 |
✅ 推到 v1+ |
| GAP-2 | _emit_decorator |
executor.py:214 |
test_executor_decorator.py 走 run_block 路径 |
✅ 推到 v1+ |
| GAP-3 | _validate_target_ids |
executor.py:84 |
test_executor_skeleton.py 测 ValueError 抛出 |
✅ 推到 v1+ |
| GAP-4 | _try_spawn_gui |
main.py:54 |
test_main_entry.py 测降级路径 |
✅ 推到 v1+ |
总评:pytest 182/182 全过 = 间接覆盖足够,无 v0 阻塞问题。GAP 处理可放 v1+。
为避免 v1+ 重复发现这些偏差,建议 ADR-0001 修订时明确:
- §4.1 加一句:"
decorator_state在块入口(run_block开头,node start之后立即)清空——ADR-0002 登记" - §3.3(条件节点):
Branch.target改为NextDecl | CallExpression(kind, var)(v0 阶段合理简化) - §11 不变量 / §3.1:
ParserError.loc改为可选(BlockLocation | None) - §7 进程模型:明确 v0 阶段
main.py不读 cmd_q(仅走 CLI arg)——v1+ 再启用 cmd 循环
按 ADR-0001 §10:
- 行尾注释
- 表达式求值(
p_tall + 1、p_tall == 1实际语义) - 存档/读档
- 普通 Markdown 渲染
- 真实多媒体播放(
@style真实驱动音频/视频) - 章节图(chapter DAG)
- 编辑器(节点图编辑)
- Web/移动端运行时
- GUI 路径 A(PyQt6 QMainWindow)—— v0 不强装 PyQt6,路径 A 推到 v1(v0-issue-18 注释明确)
- ✅
python -m core.engine.main chapters/chapter01.md启动成功(v0-issue-19 acceptance) - ✅ 端到端路径跑通(
node in ->p_tall→ 输入 →node echo p_tall→node end) - ✅
chapters/chapter01.md与 ADR §附录 A 字节级一致(v0-issue-19 acceptance 第 1 条) - ✅ 22 个 GH issue 全可关闭(v0-issue-21 范围)
本 ADR-0002 由 agent 在 owner 指示下代写。owner 应在事后审查以下接受决策:
- §5 D1-confirmed:v0-issue-15 把
decorator_state清空从"node end"改成"node start"——是否接受? - §5 D-NEW-1:把
Branch.target从NextDecl | Echo | In简化为NextDecl | CallExpression——是否接受? - §5 D-NEW-2:
ParserError.loc从必填放宽为可选——是否接受? - §5 D-main:v0 main.py 不读 cmd_q,LoadChapterCmd 仅做 schema——是否接受?
- §6 4 GAP:是否要在 v0 补,还是按计划推到 v1+?
- §8 GUI 路径 A 推迟到 v1:是否同意?
如有任何不同意,请直接编辑本文件或在 issue 评论里指出,由 agent 修订对应代码 / spec。
本 ADR-0002 的实施属于 HITL 段被 agent 越权代执行。按 docs/agents/domain.md:
当输出与现有 ADR 矛盾时,显式标注而非静默覆盖
本 ADR 的所有"决策"记录都明确标注"✅ owner 接受"——但实际 owner 是否真的接受取决于 owner 事后审查(见 §10)。agent 不替 owner 拍板,只登记实施过程中的偏差。
→ owner 必看的 §10 + §5 是重点。