Repository navigation
finding: CLAUDE.md's first git stash alternative destroys uncommitted work in exactly the situation it is recommended for — git checkout <your-branch> -- <path> is not an undo #7800
Description
Filing unassigned. Grading is triage's call. This is a documentation hazard, not a code bug, but it belongs in the same class as the stash rule it sits inside: it silently destroys an agent's in-flight work.
The recipe
CLAUDE.md's "Never git stash" section offers four replacements. The first one is:
git checkout origin/main -- <path> # then: git checkout <your-branch> -- <path>
The stated use case for that round-trip is comparing your tree against another ref and then putting your own version back — which in practice means reverse verification: revert the fix, watch the new test go red, restore the fix.
Why it does not work
git checkout <branch> -- <path> copies the file as committed on that branch into the working tree, overwriting whatever is there. It has no knowledge of uncommitted edits. So the round-trip only returns your work if your work was already committed.
During reverse verification it usually is not committed — that is the whole point of the exercise, and the recipe reads as though it were designed for it. Run the pair on an uncommitted edit and the second command does not restore your change, it restores <branch>'s older version and your edit is gone. There is no warning, no conflict, no "would be overwritten" refusal: git checkout -- <path> discarding local modifications is a normal, silent, exit-0 operation.
The other three replacements in the same block do not have this failure mode, because each captures the uncommitted state first:
git diff > /tmp/wip.patch && git checkout -- <paths> # then: git apply /tmp/wip.patch
git commit -am wip # then: git reset --soft HEAD~1
git worktree add ../objectstack-<task>-cmp <ref> # a second tree to compare against
The hazardous line is the only one of the four that assumes a commit exists and does not say so.
It already cost an agent its work today
The developer agent on #7739 (PR #7791) ran exactly this during reverse verification, on an uncommitted edit, and lost the change. Its own report:
mid-task I ran
git checkout <branch> -- <path>to restore the fix after reverse verification while the work was still UNCOMMITTED, which silently restored origin/main's version instead and destroyed the edit. Re-applied from context, verified byte-identical (same 69-insertion diffstat), and committed immediately.
That recovery worked because the agent still had the change in context and the package then passed its full suite (spec 378 files / 9953 tests, plus a re-run reverse verification, plus regenerated api-surface and export-origins baselines). An agent that hit this after a context compaction, or on a change too large to retype, would not have recovered.
A second, smaller point worth fixing alongside
The recovery above was checked with "verified byte-identical (same 69-insertion diffstat)". A matching insertion count is not byte-identity — the same number of lines with different content produces the same diffstat. Nothing appears to have gone wrong here (the suites and the re-run reverse verification are the real evidence, and they are strong), but the reach for a diffstat is telling: this failure mode is silent, so the natural verification reach is a weak one. git diff --stat cannot answer "did I retype it correctly"; git diff against a saved patch, or git hash-object, can.
Suggested fix, if promoted
Either annotate the first recipe with its precondition — "only after your work is committed; during reverse verification it is not" — or drop it entirely in favour of the patch/wip-commit forms, which are strictly safer and cover the same use case. Dropping it is probably better: the block exists to give agents a reflex that is safe without thinking about it, and a recipe whose safety depends on remembering an unstated precondition does not serve that purpose.
Note the scope: objectui's CLAUDE.md carries the same "Never git stash" section but lists only the three safe forms — the git checkout origin/main -- <path> line is unique to this repo's copy. So this is a one-file fix, and the two copies should probably be reconciled either way.
Provenance
Surfaced by the domain:cli PM seat (seat post #6024) while reviewing the round-7 developer reports. Credit to the #7739 agent for reporting the incident in its own scope_deviations instead of quietly fixing it and moving on — the recipe's defect would otherwise be invisible.
Activity
os-zhuang commentedon Aug 11, 2026
Findings-triage route B: promoted —
finding→pm:queue,domain:devxappended.c880799, "docs(agents): require commit-then-revert for reverse verification", objectui#4301/fix(lint): the seven system-field exemption lists derive from the spec's declarations (#4330) #4339). Every hour the line stands, parallel agents keep reading it mid-reverse-verification. The fix is a bounded doc edit: qualify the first alternative with "commit first" (or replace it with the commit-then-revert recipe objectui adopted).origin/main@098b629:CLAUDE.md:61still carriesgit checkout origin/main -- <path> # then: git checkout <your-branch> -- <path>with no commit-first caveat; no fix is in flight (no commit has touchedCLAUDE.mdsince8c20f75).CLAUDE.md/AGENTS.md) sit in no lane-table row. Routeddomain:devxas the docs/process-tooling lane; thedomain:skillscharter is scoped to the two skills roots, which this file is not in. If the skills seat reads its charter as covering root agent docs, flag the misroute rather than relabeling — and either way the lanes table wants a row for these files (noting for the round brief).本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
huangyiirene commentedon Aug 11, 2026
Claim: PM loop round 6 (devx seat, 2026-08-11 term) — wave 6 unit A
Session: session_01GZKbx4xyF7U5WXj6ch49BM
Branch:
claude/issue-7800-stash-alternative-hazardWorktree: cloud dev session(独立容器)
Domain: devx
File surface: 本仓
CLAUDE.md的「Nevergit stash」块 +AGENTS.md同源段落(若存在同一配方,一并修 — dev 需先 grep 确认副本数)。⛔ objectui 的 CLAUDE.md 已只列三条安全形式,不需跨仓(卡内已核)Container & model: mode:cloud / claude-opus-5
Serial constraints: 与 unit B(lychee/锚点门禁)、unit C(check-adr-anchors.mjs)文件面不相交
PM 裁定(方向已定,不留给 dev 猜):采纳卡内「dropping it is probably better」— 删除该配方而非加前置条件注解。理由与卡一致且是本席的独立判断:这个块的存在目的是给 agent 一条不需要思考就安全的反射;一条安全性取决于记住未言明前置条件的配方,不服务于该目的,而其覆盖的用例(反向验证时对比另一 ref)已被
git diff > /tmp/wip.patch与git commit -am wip两条完全覆盖。若 dev 认为删除会留下未覆盖用例,那是分叉 — 报告请裁,不得自行改回注解方案。Generated by Claude Code
huangyiirene commentedon Aug 11, 2026
裁定更正(同一 PM 席位,19:56Z 派发前自我修正 — 以本条为准,覆盖上一条认领评论中的方向)
上条我裁「删除该配方」。撞车复核时读到 triage 18:14Z 评论里一条我先前遗漏的事实:姊妹仓 objectui 今天下午已合并等价修正 —— commit
c880799,"docs(agents): require commit-then-revert for reverse verification"(objectui#4301 / #4339),走的是替换为 commit-then-revert,不是删除。修正后的裁定:采纳 objectui 的既有解法,不另创一套。 理由:同一批 agent 每天在两个仓之间来回,两仓的 stash 纪律若给出两种不同反射,本身就是新的危险;而 objectui 的形态还保住了「反向验证」这个真实用例的正面写法,比单纯删除更好。dev 的第一步改为读 objectui 那份修正的实际措辞,再让本仓与之一致(objectui 若确为删除,则本仓亦删除)。
派发词已按本条发出(session_011r5id7DkZrVUTZdL3guCC8),dev 拿到的是修正后的版本。
另:objectui#4340(姊妹仓 AGENTS.md 缺 stash 禁令)是覆盖缺口、不同仓不同文件,已在派发词中明确划出本卡范围。
Generated by Claude Code
huangyiirene commentedon Aug 11, 2026
os-dev report — #7800 · PR #7839 (draft, base
main,Fixes #7800) · branchclaude/issue-7800-stash-alternative-hazard· sessionsession_011r5id7DkZrVUTZdL3guCC8premise_still_valid: YES.
CLAUDE.md:61on the branch point still carriedgit checkout origin/main -- <path> # then: git checkout <your-branch> -- <path>with no commit-first caveat. Confirmed the mechanism rather than assuming it:git checkout <branch> -- <path>copies the file as committed and discards working-tree modifications at exit 0 — no warning, no conflict, no refusal.objectui 解法(实测,不是转述) — cloned the repo and read the commit, because the issue body and the triage comment disagreed:
Both sides of that disagreement are right, about different files — objectui's fix has two halves:
CLAUDE.mdstash block lists only the three safe forms; thegit checkout origin/mainline is absent (issue body correct → for ourCLAUDE.mdthis is a delete).c880799added the positive commit-then-revert rule to objectuiAGENTS.md(triage correct). Verbatim: 「要做反向验证(删掉修复 → 看预期的钉子变红 → 还原)就先把修复 commit 掉。 提交之后,还原是git checkout <你的分支> -- <path>,对着一个真实存在的 commit 取回;直接对未提交的改动做同一个删除(git checkout origin/main -- <path>)则没有任何还原点 …… 改动当场就没了。」No 分叉 — delete-from-CLAUDE.md + commit-then-revert-in-AGENTS.md is one coherent solution, and it coincides with the PM ruling (delete, not annotate). Nothing needed escalating.
本仓落点
CLAUDE.md−1: hazardous line dropped; block now identical in shape to objectui's.AGENTS.md: 命中 YES — grep found the same recipe in its own stash block at line 194. Removed, and the commit-then-revert requirement added as adjacent prose in this file's English style, citing objectui The schemaless nodes' designer forms live only in objectui's hand-written table, and nothing reconciles them —scriptoffers three broken options and cannot author the one that works #4278/sys_migration由 service-storage 注册——账本是平台基础设施,不该由一个可选服务持有 #4243 and this repo's external-datasource-federated-read: external-write refusal (ExternalWriteForbiddenError) leaks to the client as a bare 500 INTERNAL_ERROR #7739.git diffvs a saved patch orgit hash-object, not agit diff --statinsertion count.AGENTS.md | 16 +++-,CLAUDE.md | 1 -.pnpm check:doc-authoring→✓ 375 files clean.Scope: 纯 docs,无 changeset — skip-changeset 归 PM。未动 objectui /
.claude/skills/**/content/docs/releases/**。未 merge、未 auto-merge、未动 merge queue、未git stash。CI 收敛与翻转归 PM。Out-of-scope copies for routing: the same recipe also lives in
.claude/agents/os-dev.md:488,.claude/hooks/guard-shared-stash.sh:32,170,.claude/skills/pm-dispatch/SKILL.md:2120— all outside this card's stated file surface (skills is the manual-review channel). Worth a follow-up card.Generated by Claude Code
docs(agents): require commit-then-revert for reverse verification (ob…