首页
/ Claw Code G013 验证地图:Pinpoint 693–695 的类型化错误、本地 pre-push 构建门禁与启动预检诊断

Claw Code G013 验证地图:Pinpoint 693–695 的类型化错误、本地 pre-push 构建门禁与启动预检诊断

2026-09-04 16:21:33作者:翟萌耘Ralph

本文围绕仓库中的 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 分别对应三个不同的可靠性问题:

  • #693claw-analog 的 RAG/bootstrap-plan 解析对缺失或无法识别的 phase 字段静默降级为 "unknown",缺少类型化错误(ROADMAP 称之为 "classifier-orphan pattern",此前在 #422、#463 中已出现两次)。
  • #694main 上曾静默累积多处编译错误(如枚举字段删除后仍有引用、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)。它的处理顺序是:

  1. 解析响应体为 JSON,失败则返回 invalid JSON: {e}
  2. 读取 phase 字段并断言其为字符串——缺失或非字符串时返回 unknown_bootstrap_phase_errorreceived_value 取实际收到的值(或 null),消息为 RAG response is missing a string phase; refusing to silently render phase as unknown
  3. 断言 phase 在白名单内,否则同样返回类型化错误,消息为 RAG response phase is not a recognized bootstrap phase
  4. 校验通过后才渲染 hits 数组(含 scorepath、最多 32 行 snippet)。

在工具调用链上,retrieve_context_toolrust/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.rsretry_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=1skipping 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_warningsrust/crates/runtime/src/worker_boot.rs#L1118-L1150)接收工作目录与任务提示词,产出 WorkerStartupPreflightWarning 列表,检查顺序为:

  1. git 元数据可写性git_metadata_pathL1194-L1213)先执行 git rev-parse --git-dir 解析出 .git 位置(相对路径会拼接到 cwd 上),再由 path_is_writable 探测;不可写则发出 GitMetadataNotWritable 告警,消息形如 git metadata is not writable; commits or pushes may fail: <path>
  2. 任务提及的路径是否被当前分支跟踪mentioned_repo_pathsL1152-L1181)从任务提示词中抽取候选仓库路径,规则相当保守——token 必须包含 /、不能是 URL(含 ://)、不能以 / 开头(避免绝对路径误报)、不能含 ..、只能由 ASCII 字母数字与 /_-. 组成、且最后一段必须带扩展名,并做去重。随后 git_tracks_pathL1183-L1192)对每个候选执行 git ls-files --error-unmatch -- <path>,失败即说明该路径未被当前分支跟踪,发出 FileAbsentOnBranch 告警,消息为 task mentions <path>, but git does not track it on the current branch

告警的接入点在 WorkerRegistry::observe_startup_preflightrust/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.pyscripts/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 fmtcargo testcargo 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 自主维护场景下保持主干可编译、可诊断的关键机制。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
981
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384