Claw Code G013 验证地图:Pinpoint 693–695 的类型化错误、本地 pre-push 构建门禁与启动预检诊断
本文围绕仓库中的 G013 验证地图 docs/g013-roadmap-pinpoints-693-695-verification-map.md 展开,该地图记录了 main 重置回 origin/main 后新发现的三个 ROADMAP Pinpoint(#693–#695)的落地状态。读完后,你将掌握 Claw Code 中 RAG 解析层如何拒绝静默的 "unknown" 回退、本地 Git hook 如何把 CI 构建门禁镜像到 git push 之前、以及 runtime crate 如何在模型第一次响应前输出结构化预检告警——并拿到一套可直接执行的验证命令清单。
背景:G013 验证地图与 ROADMAP Pinpoint 的关系
Claw Code 的仓库维护流程中,ROADMAP.md 会持续追加以 ## Pinpoint #xxx 为标题的问题条目,每个条目描述一个被探针(probe)发现的具体缺陷、影响面与"Required fix shape"(期望的修复形态)。G013 这类"verification map"文档则用于记录:这些 Pinpoint 在当前代码头(current head)上已经被哪些代码、hook 和回归测试覆盖,以及用哪些命令可以复验。
本次 G013 记录的触发条件是:main 被重置回 origin/main 之后,发现 ROADMAP.md 中存在三个未被 Claw Code 2.0 看板(CC2 board)覆盖的新 Pinpoint 标题。三个 Pinpoint 分别对应三个不同的可靠性问题:
- #693:
claw-analog的 RAG/bootstrap-plan 解析对缺失或无法识别的phase字段静默降级为"unknown",缺少类型化错误(ROADMAP 称之为 "classifier-orphan pattern",此前在 #422、#463 中已出现两次)。 - #694:
main上曾静默累积多处编译错误(如枚举字段删除后仍有引用、variant 删除后仍被构造),原因是 CI 构建目录配置本身一度损坏,且本地没有任何 push 前的构建门禁。 - #695:Agent 会话可能启动在过期的本地 worktree 中,任务里引用的文件在当前分支并不存在,Agent 会白白烧掉一整轮探索才发现自己站错了树;另一层问题是沙箱外的
.git元数据不可写,代码改完了却提交不了。
以下三个小节逐一给出每个 Pinpoint 的代码证据与回归测试。
Pinpoint #693:用类型化错误替代静默 unknown
问题本质与修复位置
问题位于 claw-analog crate(rust/crates/claw-analog/src/lib.rs)。claw-analog 是一个精简的 agent harness:当配置了 RAG 服务地址(TOML 的 rag_base_url 或环境变量 RAG_BASE_URL)时,它会向 claw-rag-service 暴露 retrieve_context 工具并调用 POST {base}/v1/query。原始实现中,响应解析使用 .unwrap_or("unknown")——只要 RAG 响应 JSON 缺少 phase 字段或值不被识别,事件就静默地以 "unknown" 渲染,没有 kind 判别字段,也没有任何结构化提示。自动化管线如果按特定 phase 过滤事件,就会在毫无错误信号的情况下漏掉它们。
类型化错误信封的实现
修复的核心是一个白名单常量与一个错误信封构造函数(rust/crates/claw-analog/src/lib.rs#L1112-L1124):
const KNOWN_RAG_BOOTSTRAP_PHASES: &[&str] =
&["1-sqlite-no-db", "1-sqlite-empty", "1-sqlite", "2-qdrant"];
fn unknown_bootstrap_phase_error(received_value: Value, message: &str) -> String {
json!({
"kind": "unknown_bootstrap_phase",
"field": "phase",
"received_value": received_value,
"allowed_values": KNOWN_RAG_BOOTSTRAP_PHASES,
"message": message,
})
.to_string()
}
错误信封包含五个字段:kind(判别器,恒为 "unknown_bootstrap_phase")、field(出错的字段名 "phase")、received_value(实际收到的原始值,缺失时为 null)、allowed_values(合法的四个 bootstrap phase)、以及人类可读的 message。
format_rag_query_json_for_model 是执行校验的入口(rust/crates/claw-analog/src/lib.rs#L1126-L1139)。它的处理顺序是:
- 解析响应体为 JSON,失败则返回
invalid JSON: {e}; - 读取
phase字段并断言其为字符串——缺失或非字符串时返回unknown_bootstrap_phase_error,received_value取实际收到的值(或null),消息为RAG response is missing a string phase; refusing to silently render phase as unknown; - 断言
phase在白名单内,否则同样返回类型化错误,消息为RAG response phase is not a recognized bootstrap phase; - 校验通过后才渲染
hits数组(含score、path、最多 32 行 snippet)。
在工具调用链上,retrieve_context_tool(rust/crates/claw-analog/src/lib.rs#L1171-L1217)负责发送 HTTP 请求并把响应体交给该函数格式化;解析失败时不会吞错,而是把类型化错误连同原始响应一起回传给模型:
match format_rag_query_json_for_model(&text) {
Ok(s) => s,
Err(e) => format!("error: {e}\nraw: {text}"),
}
这使得 Agent 在下一轮能直接依据 kind / received_value / allowed_values 判断是 RAG 服务端 phase 命名漂移,还是请求格式问题,而不是面对一个无差别的 "unknown"。
回归测试
rust/crates/claw-analog/src/lib.rs#L2586-L2607 中有三个测试锁住该契约:
rag_response_missing_phase_returns_typed_error:输入{"hits":[]},断言错误包含"kind":"unknown_bootstrap_phase"与"field":"phase";rag_response_unknown_phase_returns_typed_error:输入{"hits":[],"phase":"unknown"},额外断言"received_value":"unknown";rag_response_unrecognized_phase_returns_typed_error:输入{"hits":[],"phase":"3-drifted"},额外断言错误中包含allowed_values列表。
验证时可直接运行(见文末命令清单):cargo test --manifest-path rust/Cargo.toml -p claw-analog rag_response_ -- --nocapture。
Pinpoint #694:本地 pre-push 构建门禁
为什么要镜像 CI 门禁
按 ROADMAP.md 中 Pinpoint #694 的记载,main 曾同时静默累积三处编译错误:openai_compat.rs 在 retry_after 字段被删除后仍引用 ApiError::Api { retry_after: None }(3 处)、commands crate 仍构造已删除的 SlashCommand::Team variant、rusty-claude-cli 初始化 StatusContext 时缺少 config_load_error_kind。它们之所以能"安静地"留在主干上,是因为 CI 构建任务的 working-directory 配置本身一度损坏,而本地也没有任何 hook 在 push 前强制执行 cargo build --workspace。后果是:任何 rebase 到坏掉的 main 上的 PR 都会继承这些编译错误,让 CI 在本来正确的代码上报告无关失败。
hook 脚本逐项解析
门禁实现是一个 Bash 脚本 .github/hooks/pre-push,完整内容如下(全文 31 行):
#!/usr/bin/env bash
# Claw Code local pre-push safety gate.
#
# Install with:
# git config core.hooksPath .github/hooks
set -euo pipefail
repo_root="$(git rev-parse --show-toplevel 2>/dev/null)"
cd "$repo_root"
if [[ -x scripts/roadmap-check-ids.sh ]]; then
echo "pre-push: scripts/roadmap-check-ids.sh" >&2
scripts/roadmap-check-ids.sh >&2
fi
if [[ "${SKIP_CLAW_PRE_PUSH_BUILD:-}" == "1" ]]; then
echo "pre-push: SKIP_CLAW_PRE_PUSH_BUILD=1 set; skipping cargo workspace build" >&2
exit 0
fi
if [[ ! -f rust/Cargo.toml ]]; then
echo "pre-push: rust/Cargo.toml not found; skipping cargo workspace build" >&2
exit 0
fi
build_cmd=(cargo build --manifest-path rust/Cargo.toml --workspace --locked)
echo "pre-push: ${build_cmd[*]}" >&2
"${build_cmd[@]}"
关键设计点:
- 安装方式:
git config core.hooksPath .github/hooks。这是一条仓库内可见、可随版本库分发的安装命令,把 Git 的 hook 查找路径指到仓库内的.github/hooks目录。 set -euo pipefail:任何一步失败即中止 push;- roadmap 检查先行:hook 在构建之前会执行 scripts/roadmap-check-ids.sh(若存在且可执行),保证 ROADMAP 编号规范在 push 前被校验;
- 逃生舱(escape hatch):环境变量
SKIP_CLAW_PRE_PUSH_BUILD=1使 hook 打印明确的跳过提示并exit 0,而不是静默绕过; - 防御性跳过:若当前树没有
rust/Cargo.toml(例如非 Rust 的子模块检出),打印说明后退出,避免误伤; - 构建命令:
cargo build --manifest-path rust/Cargo.toml --workspace --locked。--workspace覆盖rust/下的全部 crate(api、runtime、claw-analog 等),--locked强制要求Cargo.lock与 manifest 一致,从而在本地复现 CI 的锁定依赖行为——字段/variant 陈旧引用、依赖漂移都会在 push 之前暴露。
契约测试
tests/test_pre_push_hook_contract.py 用 Python unittest 把 hook 的"契约"锁死,防止后续修改破坏行为:
test_skip_escape_hatch_exits_successfully_with_stderr_notice:在SKIP_CLAW_PRE_PUSH_BUILD=1环境下真实执行bash .github/hooks/pre-push,断言退出码为 0、stdout 为空、stderr 同时包含SKIP_CLAW_PRE_PUSH_BUILD=1和skipping cargo workspace build——确认逃生舱既生效又"响亮";test_default_build_gate_uses_workspace_locked_cargo_build:静态读取 hook 源码,断言其中包含字面命令cargo build --manifest-path rust/Cargo.toml --workspace --locked以及build_cmd=(...)数组形式——确认门禁没有降级成非锁定或单 crate 构建。
运行 python3 tests/test_pre_push_hook_contract.py -v 即可复验;此外 bash -n .github/hooks/pre-push 可做纯语法检查。
Pinpoint #695:启动/worktree 预检诊断
问题场景
Pinpoint #695 描述的失败模式是:一个 Codex/claw-code 会话被带着"修改 rust/crates/runtime/src/trident.rs"这样的任务启动,但本地 clone 是旧的 main,该文件在当前分支上根本不存在(文件只在后续提交或 feature 分支中出现)。Agent 会静默地在错误的树里搜索整整一轮才意识到站错了地方;次要摩擦是修正性提示被误发到宿主 shell(zsh: command not found: Do);第三层问题是 /tmp 中的 detached worktree 的 .git 指向沙箱可写边界之外的共享仓库路径,代码改完却 git commit 失败。
期望的修复形态(来自 ROADMAP.md 的 "Required fix shape")是:对任务中提到的每个文件路径执行 git ls-files --error-unmatch <path>,在第一次 LLM 调用前发出 kind:"file_absent_on_branch" 结构化告警;在沙箱初始化时暴露 .git 可写性检查,失败时发出 kind:"git_metadata_not_writable" 并附带路径。
实现细节
实现在 runtime crate 的 rust/crates/runtime/src/worker_boot.rs。核心函数 startup_preflight_warnings(rust/crates/runtime/src/worker_boot.rs#L1118-L1150)接收工作目录与任务提示词,产出 WorkerStartupPreflightWarning 列表,检查顺序为:
- git 元数据可写性:
git_metadata_path(L1194-L1213)先执行git rev-parse --git-dir解析出.git位置(相对路径会拼接到cwd上),再由path_is_writable探测;不可写则发出GitMetadataNotWritable告警,消息形如git metadata is not writable; commits or pushes may fail: <path>。 - 任务提及的路径是否被当前分支跟踪:
mentioned_repo_paths(L1152-L1181)从任务提示词中抽取候选仓库路径,规则相当保守——token 必须包含/、不能是 URL(含://)、不能以/开头(避免绝对路径误报)、不能含..、只能由 ASCII 字母数字与/_-及.组成、且最后一段必须带扩展名,并做去重。随后git_tracks_path(L1183-L1192)对每个候选执行git ls-files --error-unmatch -- <path>,失败即说明该路径未被当前分支跟踪,发出FileAbsentOnBranch告警,消息为task mentions <path>, but git does not track it on the current branch。
告警的接入点在 WorkerRegistry::observe_startup_preflight(rust/crates/runtime/src/worker_boot.rs#L355-L366):它对 startup_preflight_warnings(Path::new(&worker.cwd), task_prompt) 的每条结果记录一条结构化事件,时机在第一次模型轮次(first model turn)之前,保证 Agent 和运维都能在开始干活前看到"你大概率在错误的树里"的信号。
回归测试
验证地图记录了两个回归测试:
startup_preflight_warns_when_task_file_is_absent_on_branch:构造任务提示词引用一个当前分支不存在的文件,断言startup_preflight_warnings产出FileAbsentOnBranch告警;startup_preflight_records_structured_warning_event:断言observe_startup_preflight把告警落成结构化事件(而非仅打印文本)。
两者都位于 rust/crates/runtime/src/worker_boot.rs 的测试模块内,可用 cargo test --manifest-path rust/Cargo.toml -p runtime startup_preflight -- --nocapture 过滤执行。
验证命令清单
G013 文档给出的完整验证命令如下,可按顺序执行以复验三个 Pinpoint 的当前状态:
python3 scripts/generate_cc2_board.py
python3 scripts/validate_cc2_board.py --board .omx/cc2/board.json
python3 .omx/cc2/validate_issue_parity_intake.py .omx/cc2/issue-parity-intake.json
bash -n .github/hooks/pre-push
python3 tests/test_pre_push_hook_contract.py -v
cargo fmt --manifest-path rust/Cargo.toml --all -- --check
cargo test --manifest-path rust/Cargo.toml -p claw-analog rag_response_ -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p runtime startup_preflight -- --nocapture
cargo build --manifest-path rust/Cargo.toml --workspace --locked
各命令的覆盖关系:
| 命令 | 验证对象 |
|---|---|
generate_cc2_board.py / validate_cc2_board.py |
CC2 看板重新生成与结构校验(scripts/generate_cc2_board.py、scripts/validate_cc2_board.py) |
.omx/cc2/validate_issue_parity_intake.py |
issue 平行度接收(parity intake)清单校验 |
bash -n .github/hooks/pre-push |
pre-push hook 的 Bash 语法检查(#694) |
tests/test_pre_push_hook_contract.py -v |
逃生舱与 --locked 构建命令契约(#694) |
cargo fmt --all -- --check |
全仓库格式检查 |
cargo test -p claw-analog rag_response_ |
类型化 phase 错误回归测试(#693) |
cargo test -p runtime startup_preflight |
启动预检告警回归测试(#695) |
cargo build --workspace --locked |
与 pre-push 门禁、CI 完全一致的整工作区锁定构建 |
其中 .omx/cc2/ 下的看板与 intake 文件是仓库维护流程的中间产物路径(由验证文档原样给出),不在本仓库源码树中逐一展开;cargo fmt、cargo test 与 cargo build 命令要求本机具备可用的 Rust 工具链,且建议在仓库根目录下执行。
小结
G013 验证地图展示的是一组典型的"让缺陷无法静默存活"的工程手法:#693 用带 kind/received_value/allowed_values 的类型化错误信封取代 unwrap_or("unknown"),让解析层失配变成可判别的信号;#694 用一条可分发、可被契约测试锁定的 pre-push hook 把 CI 构建门禁前移到每次 push;#695 用 git ls-files --error-unmatch 与 .git 可写性探测在模型第一次响应前输出结构化预检告警。三者共同点都是"结构化、可回归测试、有明确逃生舱或提示",这正是该仓库在 Agent 自主维护场景下保持主干可编译、可诊断的关键机制。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00