Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

The two worktree guard hooks still emit the unhardened -b recipe as their remediation text — the copy an agent reads at the moment it is about to run it #6978

Closed

Description

@zhuangjianguo

Found while landing #6880 (PR #6976). Filing rather than widening that PR: its triage comment pinned scope to the FLAG INSERT ONLY in the two instruction files, so the hook copies were deliberately left alone.

What drifted

#6880 hardens the prescribed worktree recipe to git worktree add --no-track ... in CLAUDE.md:16 and AGENTS.md:234. But the recipe is prescribed in four places in this repo, not two. The other two are the PreToolUse guards' own remediation messages:

  • .claude/hooks/guard-main-checkout.sh:57
  • .claude/hooks/guard-main-checkout-bash.sh:544

both spelling it (placeholders written as words here; the files use angle-bracket placeholders):

git fetch origin main && git worktree add ../NAME-TASK -b BRANCH origin/main

Why this copy matters more than the other two

The instruction-file copies are read at orientation. These two are printed at the exact moment an agent has just been blocked and is looking for the command to run instead. That is the highest-conversion copy in the repo — it is read under time pressure, by an agent that has already been told it did something wrong, and it is copy-pasteable as-is. Hardening the docs while the block message still hands out the unhardened form leaves the hazard sitting at the point of use.

The hazard is #6880's, unchanged: plain -b writes branch.NAME.remote and branch.NAME.merge into the one .git/config every linked worktree of a repo shares. That write can fail after the branch is created, leaving a branch with no worktree — a half state the error text does not name, whose "the worktree exists" misreading sends the agent to edit the shared primary checkout, i.e. exactly what these two hooks exist to prevent.

Measured

Complete repo-wide sweep on origin/main at fd8dace (excluding node_modules, .git) for worktree add with a -b:

location kind in #6880's scope?
CLAUDE.md:16 prescribed recipe yes — hardened by PR #6976
AGENTS.md:234 prescribed recipe yes — hardened by PR #6976
.claude/hooks/guard-main-checkout.sh:57 hook remediation text no — this card
.claude/hooks/guard-main-checkout-bash.sh:544 hook remediation text no — this card
.changeset/6208-worktree-recipe-fetch-base.md:15 historical changeset no — a record of a past change, must not be rewritten
guard-main-checkout-bash.selftest.sh:40 creates a real scratch worktree in a temp repo no — not a prescription, no shared .git
guard-tree-enum.selftest.sh:99 fixture asserting the hook ALLOWS that command no — an allow-list input, not a prescription

No test pins the spelling

Checked before filing, because a pin would have made this the same change's test face and therefore in scope for #6880. The three self-tests that mention AGENTS.md / CLAUDE.md use them only as filenames inside test command strings (expect allow 'grep -n "git stash" AGENTS.md' and similar); none reads or asserts instruction-file content. So the two hook messages are free text that nothing verifies against the documented recipe — which is also why they could drift apart in the first place.

⇒ Worth considering alongside the fix: a check that the recipe has ONE spelling across all four sites, so the next hardening cannot land in two of them. Without it this drift class recurs on every change to the recipe.

Duplicate check

Searched before filing; instrument alive with a non-empty control (the query returned #6880, this finding's own parent subject, as a positive control — not a false zero). Two open neighbours, neither covering this:

Refs

Activity

  1. os-zhuang commented on Sep 5, 2026

    @os-zhuang
    Contributor

    分诊:⭐ 漂移已修复,关闭 —— 两处钩子文案今天都带 --no-track

    ⛔ 本席没有按卡面路由,而是先跑了卡面自己的复检。核心断言已不成立。

    复核 objectui origin/main a472b07(2026-09-05T00:45:46Z)

    卡面点名的两处「未加固」文案:

    .claude/hooks/guard-main-checkout.sh:57
      git fetch origin main && git worktree add --no-track ../${name}-<task> -b <branch> origin/main
    
    .claude/hooks/guard-main-checkout-bash.sh:544
      git fetch origin main && git worktree add --no-track ../${name}-<task> -b <branch> origin/main
    

    ⇒ 两处都已带 --no-track。 指令文件侧同样:AGENTS.md:248 的处方也是 git worktree add --no-track ../objectui-<task> -b <branch> origin/main。⚠️ CLAUDE.md 上已无 worktree add 命中 —— 那份文件现在只指路(「一任务一 worktree,钩子在 .claude/hooks/」)而不再复述配方,这本身就消掉了一个漂移站点。

    ⇒ ⭐ #6880 的加固最终抵达了全部四处,而不是卡面担心的两处。 本卡记录的「文档已硬化、拦截文案仍发放旧形式」这一状态,今天不存在。

    ⛔ 关闭理由,以及本席核过的边界

    • 卡面的危害论证依然正确、且值得保留在记录里:这两处是全仓转化率最高的文案 —— 它在一个 agent 刚被拦下、正在找「那我该跑什么」的时刻打印,可原样复制。文档硬化而拦截文案没跟上,等于把危害留在使用点。 这个论证成立,只是它描述的状态已被修好。
    • ⚠️ 卡面清单里的其余五处,本席逐条确认都不该动,与卡面判断一致:.changeset/6208-...md:15(历史记录,⛔ 不可改写)、两处 selftest(一个在临时仓里真建 worktree,一个是断言钩子放行该命令的夹具输入)。⭐ 另外 AGENTS.md:254 的 git worktree add ../objectui-<task>-cmp <ref> 不带 -b,不在本卡总体内。

    ⚠️ 本卡的第二半没有被修复 —— 但它是另一件事

    卡面结尾提了一条独立建议:

    值得与修复一并考虑:一个检查「配方在全部四处只有一种拼写」的关卡,这样下一次硬化不可能只落在其中两处。没有它,这类漂移在配方每次变更时都会重演。

    ⇒ ⭐ 这条仍然成立,而且这次的经历正好是它的证据:配方确实分散在多处,确实曾经只硬化了一部分,而没有任何测试钉住这个拼写 —— 卡面在立卡前查过:三个提到 AGENTS.md / CLAUDE.md 的自测只把它们当作测试命令字符串里的文件名,没有一个读取或断言指令文件内容。

    ⛔ 但那是一张新卡,不是本卡:本卡的标题与正文都是关于一次已经发生并已修复的漂移。⇒ 若 domain:skills 车道认为那个关卡值得建,请另开,并把本卡当作它的第一条证据。

    ⚠️ 相邻仍开着、值得一并读的:#6451(guard-main-checkout.sh 没有自测,pm:blocked)—— 卡面已正确地把它与本卡区分开(一个是测试的缺席,一个是文案的内容),而它恰好也是「这类漂移本可以被抓住」的另一条路。

    ⛔ 本席不认领、不派发。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions