Uh oh!
There was an error while loading. Please reload this page.
docs(agents): generalise the shared-stash rule to all shared ref namespaces - #6222
docs(agents): generalise the shared-stash rule to all shared ref namespaces#6222yinlianghui-tw wants to merge 1 commit into
Conversation
…spaces A worktree isolates your checkout and exactly four ref namespaces — HEAD, refs/bisect, refs/worktree, refs/rewritten — and nothing else. The existing stash bullet taught the right lesson at too narrow a scope; a reader who learns only that one concludes "worktrees isolate refs, except stash". Adds refs/remotes/* (a sibling's fetch advances your origin/main, and a path-scoped checkout stages what it restores) and FETCH_HEAD (last fetch in the checkout wins; the symptom is an absence that reads as "the change is missing"). FETCH_HEAD's isolation boundary is stated as measured on git 2.43 rather than extrapolated from refs/stash. No hook: the safe forms are ordinary and the unsafe form is legitimate elsewhere.
yinlianghui-tw
commented
Aug 25, 2026
PM review — ACCEPT. ⛔ Stays a draft for |
Fixes#5700
⛔ Governed surface — this stays a draft
AGENTS.mdis a governed face under the 2026-08-18 maintainer ruling. This PR is deliberately a draft, review requested fromos-zhuang. It is not ready-flipped, has no auto-merge, and is not in the merge queue. A human lands it. Green is necessary here, not sufficient.What changes
One bullet added to
AGENTS.md§9 多 agent 协作纪律, immediately after the existinggit stashbullet, plus an empty-frontmatter changeset. 41 insertions, 0 deletions, one hunk. Nothing around it is reflowed, renumbered or re-indented.The existing stash rule teaches the right lesson at too narrow a scope. The general fact is:
refs/stashis one case of that. A reader who learns only the stash bullet concludes "worktrees isolate refs, except stash" — the opposite of the truth — so the new text references the stash bullet as its own special case rather than restating it, and adds the two further instances that have cost work:refs/remotes/*— a sibling agent's fetch advances yourorigin/main, so a path-scopedgit checkout origin/main -- PATHSrestores whatever that ref points at now, possibly newer than your branch base — another agent's merged work entering your tree under the name of a "revert". A path-scoped checkout also stages what it restores, so contamination arrives already in the index.FETCH_HEAD— the instance whose symptom the other two cannot teach: an absence, not wrong content. Agit diffagainst a movedFETCH_HEADexits 0 and prints nothing, and the natural reading is "the change is not there" — a confidently wrong review conclusion about someone else's work, on evidence that looks clean. Called out as hitting reviewing seats hardest, since comparing a PR againstmainis exactly that operation.Then three practices, stated as practices rather than prohibitions: pin
BASE=$(git rev-parse HEAD)at worktree creation and restore against that commit; if you do name a remote-tracking ref, verify the content you got by occurrence counts on disk, in both directions; fetch into a ref you own (git fetch origin BRANCH:refs/NAMESPACE/ID -f) and read that.⛔ No hook, by design
The safe forms are
git checkoutandgit fetch— ordinary commands — and the unsafe form is legitimate elsewhere, so a mechanical block would fire on correct usage. The card's own reasoning is binding on this and the new text says so explicitly. None is added and none is proposed.The dispatch order described
FETCH_HEADas living in the common.gitdirectory and being shared by every worktree. I measured it instead of copying it, and that wording is not right for linked worktrees on git 2.43. Writing it into a governed instruction file would have repeated this very card's original error — an unverified scope claim — in the opposite direction.Empirically: worktree B fetching a different branch did not move worktree A's
FETCH_HEAD; a second fetch inside A itself did replace it. So the landed text states the rule per checkout, not per worktree — the last fetch in this checkout wins — and names the real hazard site: the shared primary checkout, where reviewing seats work all day and where every agent's firstgit fetchlands before it creates a worktree. That is fully consistent with the incident recorded on the card, which happened in the shared checkout, and it explains it precisely.Verification — the positive control is the measurement
Two worktrees of this repo, A (this task's) and B (a detached probe), with a genuinely per-worktree ref contrasted against a shared one. Without that contrast "this ref is shared" and "I measured nothing" print the same thing.
--git-dir.git/worktrees/objectui-issue-5700.git/worktrees/…-probe--git-common-dir.git.gitHEAD⭐ positive control65d3e767f41b7ce3cerefs/remotes/origin/main65d3e767f65d3e767fOn disk, the same split:
.git/worktrees/NAME/HEADexists once per worktree, whilerefs/remoteshas no per-worktree copy at all — only.git/refs/remotes.FETCH_HEAD, four steps:FETCH_HEADreadmain65d3e767f0c36cd3c465d3e767f— not moved by B0c36cd3c4— replacedHEADdirectly, and verifiedrefs/remotes/*andFETCH_HEADdirectly.refs/tagsandrefs/noteswere not tested here and the landed text does not claim measurement for them. Offline man pages were unavailable in this container, so the documented list is cited as documentation, not as something I re-derived.Gates
All at final head
e5099dee7(tree42b3eed7a), each exit code captured by redirect before any pipe, each quoted from the gate's own verdict line:check-control-bytes.mjs✅ check-control-bytes: OK (scanned 5130 tracked text file(s); skipped 85 binary).check-doc-links.mjsLinks are valid across 15 scan roots.check-changeset-presence.mjs✅ No source of a released package changed in this range, so no changeset is owed.changeset:check✅ All workspace packages are in the changeset fixed group./✅ No changeset declares a major bump.pnpm lint:root✖ 28 problems (0 errors, 28 warnings)lint:rootran in full, unnarrowed. Its 28 warnings are pre-existingno-explicit-anyine2e/,scripts/__tests__/andvitest.setup.base.ts— none of them files this PR touches. Measured from eslint's own config via--format json: it lints 191 files, 0 of them.md, and neither changed file (AGENTS.md,.changeset/5700-shared-ref-namespaces.md) is in its population at all. A control-byte self-scan over the changed file (grep -naPacross the C0 range plus DEL) is clean independently of the gate.The changeset carries empty frontmatter — this repo's declaration form for a change that publishes nothing.
Coordination
###subsection at the end of §9, immediately before the### ⛔ 受管面(governed surface)heading; this PR inserts a list item in the earlier bullet run beside the stash bullet. The two regions do not overlap and neither reflows the other's context, so merge order between them is free.AGENTS.md/CLAUDE.md. That edit is the skills lane's and is out of scope here, so it is filed as the upstream twin card [process] Upstream twin of objectui#5700 — the shared-stash rule in AGENTS.md/CLAUDE.md stops one ref-namespace short; worktrees also share refs/remotes/*, and FETCH_HEAD is last-fetch-wins per checkout objectstack#11946 (unassigned,finding) — including theFETCH_HEADcorrection above, so it is not copied upstream in the unverified form.content/docs/releases/is touched.Refs: #3430 (the stash instance) · #5202 and #5235 (the remote-tracking instances) · the card's 2026-08-24 comment (the
FETCH_HEADinstance).Generated by Claude Code