Skip to content

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim - #6976

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening
Aug 31, 2026
Merged

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim#6976
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening

Conversation

@zhuangjianguo

@zhuangjianguozhuangjianguo commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6880
Part of #6866 — its half 1 stays open (implementation tracked there) and is untouched here.

Two instruction-file corrections on the same governed face, folded into one PR because they
land in the same file and would otherwise be hard-serial.

1. The worktree recipe now specifies --no-track (the anchor card)

Byte-level insert into the two prescribed spellings, net 0 lines:

  • CLAUDE.md:16 — the fenced recipe.
  • AGENTS.md:234 — the same recipe inline.

(Placeholders written as words here; the files use angle-bracket placeholders.)

Plain -b writes the new branch's upstream keys — branch.NAME.remote and
branch.NAME.merge — into the one .git/config that 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 in the very first step of the recipe, and one the error text does not
name. Read as "the whole command failed", the retry hits branch already exists and reads
as a second, unrelated problem; read as "the worktree exists", the agent starts editing the
shared primary checkout — the single thing the worktree-first rule exists to prevent.

The measured basis is the anchor card's git 2.43.0 table, cited rather than re-derived:
--no-track removes the config write and still bases the worktree on origin/main;
explicit git pull origin main is unaffected (it uses the given refspec, never
branch.NAME.merge), and git push -u origin BRANCH — already the prescribed first push —
sets an upstream one command later.

This PR ate its own dogfood: its worktree was created with the hardened recipe.

Scope pin honoured (anchor triage, comment 5473464940)

p2 · pm:queue · domain:skills — scope pinned to the FLAG INSERT ONLY. [...] ⛔ The
prose extension (naming .git/config beside refs/stash / refs/remotes/*) is NOT in
scope here: its objectstack companion #13052-A is HELD for corpus audit objectstack#13597,
and the shared-namespace prose should be shaped by that audit in both repos at once.

No shared-namespace prose was extended. .git/config appears nowhere new in the
instruction text.

2. The "no mechanical backstop" paragraph, corrected in place (#6866 half 2)

Scope pin honoured (comment 5473466315)

Half 2 [...] is a plain correction and stays dispatchable now, independent of half 1:
name the guard, its report-only-vs-blocking state (#6596 still pm:awaiting-maintainer),
and its coverage, per the paragraph's own 「它会写在这里」 promise. Governed file ⇒ draft,
human merge.

The paragraph re-derived to AGENTS.md:433 (the card's :392 had drifted). Claim by claim,
measured on this branch's base:

claim in the paragraphverdict
"this repo has NO mechanical backstop, this paragraph is all there is"FALSE — the guard workflow is live
no CODEOWNERS (verified: the file does not exist)still TRUE — absent at every candidate path
no required check on the governed surfacestill TRUE — the ruleset toggle is pending on #6596
no hook on the governed surfacestill TRUE
no post-merge audit lists governed merges for anyoneFALSE
the sibling repo's audit "does not cover this repo"FALSE — it has covered four governed repos since objectstack#9619
a violation "succeeds silently, nobody is notified"FALSE — the guard reports on every PR
"a backstop this paragraph does not name is a backstop that does not exist"self-referential closure — removed

Two of those were not in the card and turned up while reading: the audit-coverage sentence
is false for the same reason the headline claim is, and it sits in the same paragraph, so
leaving it would have meant knowingly shipping a corrected paragraph that still asserts a
measured-false absence.

⭐ The sharpest corroboration is internal: the same file already named the guard 59 lines
above
, at AGENTS.md:372-376, as the workflow a tree enumeration missed. The document
contradicted itself, and the half asserting the absence was the half written to be trusted
absolutely.

The replacement keeps every claim that is still true, then names the guard
(.github/workflows/governed-surface-guard.yml, check Governed Surface Queue Guard,
predicate in scripts/check-governed-queue-guard.mjs), states both legs — the
pull_request leg deliberately exits 0, so green does not mean ungoverned, which is the
misread this paragraph would otherwise invite — records that the refusing merge_group leg
only reports until the ruleset toggle is flipped, and points coverage at the script's own
GOVERNED_SURFACES rather than restating a closed inventory that goes stale the next time a
guard is added. That last part is the paragraph's own promise being kept in a form that
cannot rot the same way.

The divergence clause (amended at 623b713)

The paragraph's closing clause originally described the guard-vs-carve-out divergence as an
open adjudication. That was stale on arrival: the maintainer had already ruled it on
2026-08-30 (第 5 场决裁批 #7, verbatim 「批 #7 同意」 — Option A, ui#6866 comment
5469339478). The clause now records the ruling itself — published skills/** is governed,
the guard's reading is the ruled one, implementation pending on #6866 — and forbids acting
on the carve-out until that lands. The carve-out sentences at AGENTS.md:419/:421 remain
byte-identical in this PR; their Option-A rewrite is #6866's follow-up implementation,
deliberately not folded in here.

Not in this PR

Validation

Round 1 at 64d6421, amend re-run at 623b713; exit codes captured before any pipe.

checkexitverdict line
check:control-bytes0✅ check-control-bytes: OK (scanned 5804 tracked text file(s); skipped 85 binary).
check:doc-fences0✅ check:doc-fences — every TypeScript block in 224 document(s) is fenced ts/tsx/typescript
check:governed-queue-guard0OK check-governed-queue-guard self-test: 132 cases pass
check-changeset-presence.mjs0✅ No source of a released package changed in this range, so no changeset is owed.
check-doc-links.mjs0Links are valid across 17 scan roots.
all 4 hook self-tests0121 passed, 0 failed · 41 passed, 0 failed · 36 passed, 0 failed

Anchored greps with positive controls (after the amend): --no-track1 in each file;
本仓没有任何机械兜底0; 本段没点名的兜底工具0; 这一分歧在 #6866 待维护者裁决0;
批 #71; controls — 受管面 in AGENTS.md7; PreToolUse5;
guard-shared-stash.sh in CLAUDE.md1. Line totals unchanged: CLAUDE.md 51,
AGENTS.md 489 — net 0 lines in both.

The guard, run against this PR's own file list, agrees with what the new paragraph says
about it:

⛔ GOVERNED — 2 of 3 path(s) are on a governed surface:
AGENTS.md x1 — the repo-root agent instruction file
CLAUDE.md x1 — the repo-root Claude instruction file
⛔ Do not flip it ready, enqueue it, or arm auto-merge. Park it as a DRAFT and leave the
merge to the maintainer; a human merge IS the review record for a governed surface.

Landing

Governed surface ⇒ draft, human merge (pm:awaiting-maintainer per 批 #7's execution
note). ⛔ Not flipped ready, not enqueued, no auto-merge. The changeset carries empty
frontmatter — this repo's measured form for a non-publishing change (precedent:
.changeset/6208-worktree-recipe-fetch-base.md, the same change class).

Generated by Claude Code

…o-backstop claim
Two instruction-file corrections on the same governed face.
**The prescribed worktree recipe now specifies `--no-track`** (`CLAUDE.md`, `AGENTS.md`).
Plain `-b` writes the new branch's upstream keys — `branch.NAME.remote` and
`branch.NAME.merge` — into the one `.git/config` that 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 in the very first step of the recipe, and one the error text does
not name. Read as "the whole command failed", the retry hits `branch already exists` and
reads as a second, unrelated problem; read as "the worktree exists", the agent starts
editing the shared primary checkout — the one thing the worktree-first rule exists to
prevent.
Measured on git 2.43.0: `--no-track` removes the config write and still bases the worktree
on `origin/main`. Explicit `git pull origin main` is unaffected (it uses the given refspec,
never `branch.NAME.merge`), and `git push -u origin BRANCH` — already the prescribed first
push — sets an upstream one command later.
**The governed-surface section no longer claims this repo has no mechanical backstop.**
The paragraph asserted that nothing mechanical covers the governed surface here, that the
sibling repo's post-merge audit does not cover this repo, and — self-referentially — that
"a backstop this paragraph does not name is a backstop that does not exist". Measured
today, three of those claims are false: `.github/workflows/governed-surface-guard.yml` is
live and reports on every pull request, and the sibling audit has covered this repo since
objectstack#9619. The same file already named the guard 59 lines above, so the document
contradicted itself.
The replacement keeps what is still true (no CODEOWNERS, no hook, not yet a required
check), names the guard and its two legs — the `pull_request` leg deliberately exits 0, so
green does not mean ungoverned — records that it stays report-only until the ruleset
toggle is flipped, and points coverage at the script's own list instead of restating a
closed inventory that goes stale the next time a guard is added.
Net 0 lines in both files; the changeset carries empty frontmatter because no published
package's source changed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
…ause
One clause in the corrected backstop paragraph said the guard-versus-carve-out
divergence on published `skills/**` was awaiting the maintainer. It is not: the
ruling landed 2026-08-30 (director session, ruling batch 7, maintainer verbatim
「批 #7 同意」) taking Option A — published `skills/**` is governed, human merge,
with the 2026-08-26 md-versus-code split written in alongside it. The earlier
routing that described it as undecided was made from the card body alone and has
been withdrawn on the card.
The clause now states that the divergence is ruled, cites the ruling comment,
and says the guard's reading is the decided one — while noting the carve-out
text above has not yet been rewritten, so a reader must not act on it in the
meantime. Rewriting that text is the separate implementation card's job, not
this PR's.
Word-level edit inside the existing line: the paragraph stays one line, both
files keep their line totals (AGENTS.md 489, CLAUDE.md 51), and the carve-out
sentences remain byte-identical to origin/main.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:17
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit ba55fb5Aug 31, 2026
30 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6880-worktree-recipe-hardening branch August 31, 2026 07:30
os-sam pushed a commit that referenced this pull request Aug 31, 2026
Conflict resolution, one file, one hunk: the backstop paragraph.
While this branch sat in the merge queue, the maintainer landed #6976
(ba55fb5), which rewrote the same paragraph under the title "correct the
stale no-mechanical-backstop claim". That paragraph is authoritative and is
taken VERBATIM; this branch's competing rewrite of it is discarded in full,
not blended. Byte-checked: the whole paragraph up to its trailing caveat
clause is identical to origin/main (sha256 of the 1393-byte prefix matches),
including the CODEOWNERS sentence, the "尚未是 required context" sentence and
"在翻转之前,那条拒绝腿只报告、不阻止队列".
The branch's remaining edits auto-merged and are re-derived rather than
replayed: the list heading 四项 -> 五项, the new repo-root `skills/**` row
(`GOVERNED_SURFACES`'s `skills-catalog`), the docs/adr row's 上面三项 ->
上面四项 (verified: exactly 4 rows precede it), the ⚠️ block flipped to
"both skills trees are governed" while keeping `.agents/skills/` NOT governed,
and the inverted-scolding paragraph, which still taught the retired
".claude/-prefix" criterion on main and now records it as the past error.
One consequential edit beyond the branch: the maintainer's own trailing
caveat said the script's set and the list above "并不一致 ... 落地仍挂在
#6866 上,在它落地前 ⛔ 不要照上面那条豁免行事". This commit IS that landing,
so the clause is updated minimally to record the ruling as landed and the old
exemption as void. Nothing else in the paragraph is touched.
The ruling being implemented is the maintainer's 5th adjudication batch item
#7, Option A, recorded on #6866 comment 5469339478. No ruling is made here.
Verification (offline; both scripts import only node: builtins plus
scripts/invoked-as.mjs, so no install is in their closure):
node scripts/check-governed-queue-guard.mjs --self-test -> exit 0,
"OK check-governed-queue-guard self-test: 132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.md -> exit 3,
"⛔ GOVERNED — 1 of 1 path(s) are on a governed surface"
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
huangyiirene pushed a commit that referenced this pull request Aug 31, 2026
…diation text
`.claude/hooks/guard-main-checkout.sh` and `.claude/hooks/guard-main-checkout-bash.sh`
each end their block message with the worktree recipe to run instead, and both created
the branch with a plain `-b`. PR #6976 hardened the prescribed form in `CLAUDE.md` and
`AGENTS.md`; the hooks' copy was left behind — and it is the higher-leverage copy,
delivered at the exact moment an agent is about to act, so it is the one most likely to
be run verbatim.
The hazard is the one #6976 established: plain `-b` writes the new branch's upstream keys
(`branch.NAME.remote`, `branch.NAME.merge`) into the one `.git/config` that 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. Read as "the
worktree exists", the agent starts editing the shared primary checkout, which is the one
thing these two guards exist to prevent.
Additive, not a recipe rewrite: this repo's hooks already emitted the fetch-hardened base
(`git fetch origin main && … origin/main`, landed for ui#6208), so the missing flag was
the only surviving divergence from the prescribed form. One word added per file, net ±0
lines in both.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationpm:awaiting-maintainer

Projects

None yet

3 participants

@zhuangjianguo@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim by zhuangjianguo · Pull Request #6976 · objectstack-ai/objectui · GitHub
Skip to content

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim - #6976

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening
Aug 31, 2026
Merged

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim#6976
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening

Conversation

@zhuangjianguo

@zhuangjianguozhuangjianguo commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6880
Part of #6866 — its half 1 stays open (implementation tracked there) and is untouched here.

Two instruction-file corrections on the same governed face, folded into one PR because they
land in the same file and would otherwise be hard-serial.

1. The worktree recipe now specifies --no-track (the anchor card)

Byte-level insert into the two prescribed spellings, net 0 lines:

  • CLAUDE.md:16 — the fenced recipe.
  • AGENTS.md:234 — the same recipe inline.

(Placeholders written as words here; the files use angle-bracket placeholders.)

Plain -b writes the new branch's upstream keys — branch.NAME.remote and
branch.NAME.merge — into the one .git/config that 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 in the very first step of the recipe, and one the error text does not
name. Read as "the whole command failed", the retry hits branch already exists and reads
as a second, unrelated problem; read as "the worktree exists", the agent starts editing the
shared primary checkout — the single thing the worktree-first rule exists to prevent.

The measured basis is the anchor card's git 2.43.0 table, cited rather than re-derived:
--no-track removes the config write and still bases the worktree on origin/main;
explicit git pull origin main is unaffected (it uses the given refspec, never
branch.NAME.merge), and git push -u origin BRANCH — already the prescribed first push —
sets an upstream one command later.

This PR ate its own dogfood: its worktree was created with the hardened recipe.

Scope pin honoured (anchor triage, comment 5473464940)

p2 · pm:queue · domain:skills — scope pinned to the FLAG INSERT ONLY. [...] ⛔ The
prose extension (naming .git/config beside refs/stash / refs/remotes/*) is NOT in
scope here: its objectstack companion #13052-A is HELD for corpus audit objectstack#13597,
and the shared-namespace prose should be shaped by that audit in both repos at once.

No shared-namespace prose was extended. .git/config appears nowhere new in the
instruction text.

2. The "no mechanical backstop" paragraph, corrected in place (#6866 half 2)

Scope pin honoured (comment 5473466315)

Half 2 [...] is a plain correction and stays dispatchable now, independent of half 1:
name the guard, its report-only-vs-blocking state (#6596 still pm:awaiting-maintainer),
and its coverage, per the paragraph's own 「它会写在这里」 promise. Governed file ⇒ draft,
human merge.

The paragraph re-derived to AGENTS.md:433 (the card's :392 had drifted). Claim by claim,
measured on this branch's base:

claim in the paragraphverdict
"this repo has NO mechanical backstop, this paragraph is all there is"FALSE — the guard workflow is live
no CODEOWNERS (verified: the file does not exist)still TRUE — absent at every candidate path
no required check on the governed surfacestill TRUE — the ruleset toggle is pending on #6596
no hook on the governed surfacestill TRUE
no post-merge audit lists governed merges for anyoneFALSE
the sibling repo's audit "does not cover this repo"FALSE — it has covered four governed repos since objectstack#9619
a violation "succeeds silently, nobody is notified"FALSE — the guard reports on every PR
"a backstop this paragraph does not name is a backstop that does not exist"self-referential closure — removed

Two of those were not in the card and turned up while reading: the audit-coverage sentence
is false for the same reason the headline claim is, and it sits in the same paragraph, so
leaving it would have meant knowingly shipping a corrected paragraph that still asserts a
measured-false absence.

⭐ The sharpest corroboration is internal: the same file already named the guard 59 lines
above
, at AGENTS.md:372-376, as the workflow a tree enumeration missed. The document
contradicted itself, and the half asserting the absence was the half written to be trusted
absolutely.

The replacement keeps every claim that is still true, then names the guard
(.github/workflows/governed-surface-guard.yml, check Governed Surface Queue Guard,
predicate in scripts/check-governed-queue-guard.mjs), states both legs — the
pull_request leg deliberately exits 0, so green does not mean ungoverned, which is the
misread this paragraph would otherwise invite — records that the refusing merge_group leg
only reports until the ruleset toggle is flipped, and points coverage at the script's own
GOVERNED_SURFACES rather than restating a closed inventory that goes stale the next time a
guard is added. That last part is the paragraph's own promise being kept in a form that
cannot rot the same way.

The divergence clause (amended at 623b713)

The paragraph's closing clause originally described the guard-vs-carve-out divergence as an
open adjudication. That was stale on arrival: the maintainer had already ruled it on
2026-08-30 (第 5 场决裁批 #7, verbatim 「批 #7 同意」 — Option A, ui#6866 comment
5469339478). The clause now records the ruling itself — published skills/** is governed,
the guard's reading is the ruled one, implementation pending on #6866 — and forbids acting
on the carve-out until that lands. The carve-out sentences at AGENTS.md:419/:421 remain
byte-identical in this PR; their Option-A rewrite is #6866's follow-up implementation,
deliberately not folded in here.

Not in this PR

Validation

Round 1 at 64d6421, amend re-run at 623b713; exit codes captured before any pipe.

checkexitverdict line
check:control-bytes0✅ check-control-bytes: OK (scanned 5804 tracked text file(s); skipped 85 binary).
check:doc-fences0✅ check:doc-fences — every TypeScript block in 224 document(s) is fenced ts/tsx/typescript
check:governed-queue-guard0OK check-governed-queue-guard self-test: 132 cases pass
check-changeset-presence.mjs0✅ No source of a released package changed in this range, so no changeset is owed.
check-doc-links.mjs0Links are valid across 17 scan roots.
all 4 hook self-tests0121 passed, 0 failed · 41 passed, 0 failed · 36 passed, 0 failed

Anchored greps with positive controls (after the amend): --no-track1 in each file;
本仓没有任何机械兜底0; 本段没点名的兜底工具0; 这一分歧在 #6866 待维护者裁决0;
批 #71; controls — 受管面 in AGENTS.md7; PreToolUse5;
guard-shared-stash.sh in CLAUDE.md1. Line totals unchanged: CLAUDE.md 51,
AGENTS.md 489 — net 0 lines in both.

The guard, run against this PR's own file list, agrees with what the new paragraph says
about it:

⛔ GOVERNED — 2 of 3 path(s) are on a governed surface:
AGENTS.md x1 — the repo-root agent instruction file
CLAUDE.md x1 — the repo-root Claude instruction file
⛔ Do not flip it ready, enqueue it, or arm auto-merge. Park it as a DRAFT and leave the
merge to the maintainer; a human merge IS the review record for a governed surface.

Landing

Governed surface ⇒ draft, human merge (pm:awaiting-maintainer per 批 #7's execution
note). ⛔ Not flipped ready, not enqueued, no auto-merge. The changeset carries empty
frontmatter — this repo's measured form for a non-publishing change (precedent:
.changeset/6208-worktree-recipe-fetch-base.md, the same change class).

Generated by Claude Code

…o-backstop claim
Two instruction-file corrections on the same governed face.
**The prescribed worktree recipe now specifies `--no-track`** (`CLAUDE.md`, `AGENTS.md`).
Plain `-b` writes the new branch's upstream keys — `branch.NAME.remote` and
`branch.NAME.merge` — into the one `.git/config` that 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 in the very first step of the recipe, and one the error text does
not name. Read as "the whole command failed", the retry hits `branch already exists` and
reads as a second, unrelated problem; read as "the worktree exists", the agent starts
editing the shared primary checkout — the one thing the worktree-first rule exists to
prevent.
Measured on git 2.43.0: `--no-track` removes the config write and still bases the worktree
on `origin/main`. Explicit `git pull origin main` is unaffected (it uses the given refspec,
never `branch.NAME.merge`), and `git push -u origin BRANCH` — already the prescribed first
push — sets an upstream one command later.
**The governed-surface section no longer claims this repo has no mechanical backstop.**
The paragraph asserted that nothing mechanical covers the governed surface here, that the
sibling repo's post-merge audit does not cover this repo, and — self-referentially — that
"a backstop this paragraph does not name is a backstop that does not exist". Measured
today, three of those claims are false: `.github/workflows/governed-surface-guard.yml` is
live and reports on every pull request, and the sibling audit has covered this repo since
objectstack#9619. The same file already named the guard 59 lines above, so the document
contradicted itself.
The replacement keeps what is still true (no CODEOWNERS, no hook, not yet a required
check), names the guard and its two legs — the `pull_request` leg deliberately exits 0, so
green does not mean ungoverned — records that it stays report-only until the ruleset
toggle is flipped, and points coverage at the script's own list instead of restating a
closed inventory that goes stale the next time a guard is added.
Net 0 lines in both files; the changeset carries empty frontmatter because no published
package's source changed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
…ause
One clause in the corrected backstop paragraph said the guard-versus-carve-out
divergence on published `skills/**` was awaiting the maintainer. It is not: the
ruling landed 2026-08-30 (director session, ruling batch 7, maintainer verbatim
「批 #7 同意」) taking Option A — published `skills/**` is governed, human merge,
with the 2026-08-26 md-versus-code split written in alongside it. The earlier
routing that described it as undecided was made from the card body alone and has
been withdrawn on the card.
The clause now states that the divergence is ruled, cites the ruling comment,
and says the guard's reading is the decided one — while noting the carve-out
text above has not yet been rewritten, so a reader must not act on it in the
meantime. Rewriting that text is the separate implementation card's job, not
this PR's.
Word-level edit inside the existing line: the paragraph stays one line, both
files keep their line totals (AGENTS.md 489, CLAUDE.md 51), and the carve-out
sentences remain byte-identical to origin/main.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:17
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit ba55fb5Aug 31, 2026
30 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6880-worktree-recipe-hardening branch August 31, 2026 07:30
os-sam pushed a commit that referenced this pull request Aug 31, 2026
Conflict resolution, one file, one hunk: the backstop paragraph.
While this branch sat in the merge queue, the maintainer landed #6976
(ba55fb5), which rewrote the same paragraph under the title "correct the
stale no-mechanical-backstop claim". That paragraph is authoritative and is
taken VERBATIM; this branch's competing rewrite of it is discarded in full,
not blended. Byte-checked: the whole paragraph up to its trailing caveat
clause is identical to origin/main (sha256 of the 1393-byte prefix matches),
including the CODEOWNERS sentence, the "尚未是 required context" sentence and
"在翻转之前,那条拒绝腿只报告、不阻止队列".
The branch's remaining edits auto-merged and are re-derived rather than
replayed: the list heading 四项 -> 五项, the new repo-root `skills/**` row
(`GOVERNED_SURFACES`'s `skills-catalog`), the docs/adr row's 上面三项 ->
上面四项 (verified: exactly 4 rows precede it), the ⚠️ block flipped to
"both skills trees are governed" while keeping `.agents/skills/` NOT governed,
and the inverted-scolding paragraph, which still taught the retired
".claude/-prefix" criterion on main and now records it as the past error.
One consequential edit beyond the branch: the maintainer's own trailing
caveat said the script's set and the list above "并不一致 ... 落地仍挂在
#6866 上,在它落地前 ⛔ 不要照上面那条豁免行事". This commit IS that landing,
so the clause is updated minimally to record the ruling as landed and the old
exemption as void. Nothing else in the paragraph is touched.
The ruling being implemented is the maintainer's 5th adjudication batch item
#7, Option A, recorded on #6866 comment 5469339478. No ruling is made here.
Verification (offline; both scripts import only node: builtins plus
scripts/invoked-as.mjs, so no install is in their closure):
node scripts/check-governed-queue-guard.mjs --self-test -> exit 0,
"OK check-governed-queue-guard self-test: 132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.md -> exit 3,
"⛔ GOVERNED — 1 of 1 path(s) are on a governed surface"
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
huangyiirene pushed a commit that referenced this pull request Aug 31, 2026
…diation text
`.claude/hooks/guard-main-checkout.sh` and `.claude/hooks/guard-main-checkout-bash.sh`
each end their block message with the worktree recipe to run instead, and both created
the branch with a plain `-b`. PR #6976 hardened the prescribed form in `CLAUDE.md` and
`AGENTS.md`; the hooks' copy was left behind — and it is the higher-leverage copy,
delivered at the exact moment an agent is about to act, so it is the one most likely to
be run verbatim.
The hazard is the one #6976 established: plain `-b` writes the new branch's upstream keys
(`branch.NAME.remote`, `branch.NAME.merge`) into the one `.git/config` that 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. Read as "the
worktree exists", the agent starts editing the shared primary checkout, which is the one
thing these two guards exist to prevent.
Additive, not a recipe rewrite: this repo's hooks already emitted the fetch-hardened base
(`git fetch origin main && … origin/main`, landed for ui#6208), so the missing flag was
the only surviving divergence from the prescribed form. One word added per file, net ±0
lines in both.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationpm:awaiting-maintainer

Projects

None yet

3 participants

@zhuangjianguo@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim by zhuangjianguo · Pull Request #6976 · objectstack-ai/objectui · GitHub
Skip to content

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim - #6976

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening
Aug 31, 2026
Merged

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim#6976
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening

Conversation

@zhuangjianguo

@zhuangjianguozhuangjianguo commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6880
Part of #6866 — its half 1 stays open (implementation tracked there) and is untouched here.

Two instruction-file corrections on the same governed face, folded into one PR because they
land in the same file and would otherwise be hard-serial.

1. The worktree recipe now specifies --no-track (the anchor card)

Byte-level insert into the two prescribed spellings, net 0 lines:

  • CLAUDE.md:16 — the fenced recipe.
  • AGENTS.md:234 — the same recipe inline.

(Placeholders written as words here; the files use angle-bracket placeholders.)

Plain -b writes the new branch's upstream keys — branch.NAME.remote and
branch.NAME.merge — into the one .git/config that 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 in the very first step of the recipe, and one the error text does not
name. Read as "the whole command failed", the retry hits branch already exists and reads
as a second, unrelated problem; read as "the worktree exists", the agent starts editing the
shared primary checkout — the single thing the worktree-first rule exists to prevent.

The measured basis is the anchor card's git 2.43.0 table, cited rather than re-derived:
--no-track removes the config write and still bases the worktree on origin/main;
explicit git pull origin main is unaffected (it uses the given refspec, never
branch.NAME.merge), and git push -u origin BRANCH — already the prescribed first push —
sets an upstream one command later.

This PR ate its own dogfood: its worktree was created with the hardened recipe.

Scope pin honoured (anchor triage, comment 5473464940)

p2 · pm:queue · domain:skills — scope pinned to the FLAG INSERT ONLY. [...] ⛔ The
prose extension (naming .git/config beside refs/stash / refs/remotes/*) is NOT in
scope here: its objectstack companion #13052-A is HELD for corpus audit objectstack#13597,
and the shared-namespace prose should be shaped by that audit in both repos at once.

No shared-namespace prose was extended. .git/config appears nowhere new in the
instruction text.

2. The "no mechanical backstop" paragraph, corrected in place (#6866 half 2)

Scope pin honoured (comment 5473466315)

Half 2 [...] is a plain correction and stays dispatchable now, independent of half 1:
name the guard, its report-only-vs-blocking state (#6596 still pm:awaiting-maintainer),
and its coverage, per the paragraph's own 「它会写在这里」 promise. Governed file ⇒ draft,
human merge.

The paragraph re-derived to AGENTS.md:433 (the card's :392 had drifted). Claim by claim,
measured on this branch's base:

claim in the paragraphverdict
"this repo has NO mechanical backstop, this paragraph is all there is"FALSE — the guard workflow is live
no CODEOWNERS (verified: the file does not exist)still TRUE — absent at every candidate path
no required check on the governed surfacestill TRUE — the ruleset toggle is pending on #6596
no hook on the governed surfacestill TRUE
no post-merge audit lists governed merges for anyoneFALSE
the sibling repo's audit "does not cover this repo"FALSE — it has covered four governed repos since objectstack#9619
a violation "succeeds silently, nobody is notified"FALSE — the guard reports on every PR
"a backstop this paragraph does not name is a backstop that does not exist"self-referential closure — removed

Two of those were not in the card and turned up while reading: the audit-coverage sentence
is false for the same reason the headline claim is, and it sits in the same paragraph, so
leaving it would have meant knowingly shipping a corrected paragraph that still asserts a
measured-false absence.

⭐ The sharpest corroboration is internal: the same file already named the guard 59 lines
above
, at AGENTS.md:372-376, as the workflow a tree enumeration missed. The document
contradicted itself, and the half asserting the absence was the half written to be trusted
absolutely.

The replacement keeps every claim that is still true, then names the guard
(.github/workflows/governed-surface-guard.yml, check Governed Surface Queue Guard,
predicate in scripts/check-governed-queue-guard.mjs), states both legs — the
pull_request leg deliberately exits 0, so green does not mean ungoverned, which is the
misread this paragraph would otherwise invite — records that the refusing merge_group leg
only reports until the ruleset toggle is flipped, and points coverage at the script's own
GOVERNED_SURFACES rather than restating a closed inventory that goes stale the next time a
guard is added. That last part is the paragraph's own promise being kept in a form that
cannot rot the same way.

The divergence clause (amended at 623b713)

The paragraph's closing clause originally described the guard-vs-carve-out divergence as an
open adjudication. That was stale on arrival: the maintainer had already ruled it on
2026-08-30 (第 5 场决裁批 #7, verbatim 「批 #7 同意」 — Option A, ui#6866 comment
5469339478). The clause now records the ruling itself — published skills/** is governed,
the guard's reading is the ruled one, implementation pending on #6866 — and forbids acting
on the carve-out until that lands. The carve-out sentences at AGENTS.md:419/:421 remain
byte-identical in this PR; their Option-A rewrite is #6866's follow-up implementation,
deliberately not folded in here.

Not in this PR

Validation

Round 1 at 64d6421, amend re-run at 623b713; exit codes captured before any pipe.

checkexitverdict line
check:control-bytes0✅ check-control-bytes: OK (scanned 5804 tracked text file(s); skipped 85 binary).
check:doc-fences0✅ check:doc-fences — every TypeScript block in 224 document(s) is fenced ts/tsx/typescript
check:governed-queue-guard0OK check-governed-queue-guard self-test: 132 cases pass
check-changeset-presence.mjs0✅ No source of a released package changed in this range, so no changeset is owed.
check-doc-links.mjs0Links are valid across 17 scan roots.
all 4 hook self-tests0121 passed, 0 failed · 41 passed, 0 failed · 36 passed, 0 failed

Anchored greps with positive controls (after the amend): --no-track1 in each file;
本仓没有任何机械兜底0; 本段没点名的兜底工具0; 这一分歧在 #6866 待维护者裁决0;
批 #71; controls — 受管面 in AGENTS.md7; PreToolUse5;
guard-shared-stash.sh in CLAUDE.md1. Line totals unchanged: CLAUDE.md 51,
AGENTS.md 489 — net 0 lines in both.

The guard, run against this PR's own file list, agrees with what the new paragraph says
about it:

⛔ GOVERNED — 2 of 3 path(s) are on a governed surface:
AGENTS.md x1 — the repo-root agent instruction file
CLAUDE.md x1 — the repo-root Claude instruction file
⛔ Do not flip it ready, enqueue it, or arm auto-merge. Park it as a DRAFT and leave the
merge to the maintainer; a human merge IS the review record for a governed surface.

Landing

Governed surface ⇒ draft, human merge (pm:awaiting-maintainer per 批 #7's execution
note). ⛔ Not flipped ready, not enqueued, no auto-merge. The changeset carries empty
frontmatter — this repo's measured form for a non-publishing change (precedent:
.changeset/6208-worktree-recipe-fetch-base.md, the same change class).

Generated by Claude Code

…o-backstop claim
Two instruction-file corrections on the same governed face.
**The prescribed worktree recipe now specifies `--no-track`** (`CLAUDE.md`, `AGENTS.md`).
Plain `-b` writes the new branch's upstream keys — `branch.NAME.remote` and
`branch.NAME.merge` — into the one `.git/config` that 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 in the very first step of the recipe, and one the error text does
not name. Read as "the whole command failed", the retry hits `branch already exists` and
reads as a second, unrelated problem; read as "the worktree exists", the agent starts
editing the shared primary checkout — the one thing the worktree-first rule exists to
prevent.
Measured on git 2.43.0: `--no-track` removes the config write and still bases the worktree
on `origin/main`. Explicit `git pull origin main` is unaffected (it uses the given refspec,
never `branch.NAME.merge`), and `git push -u origin BRANCH` — already the prescribed first
push — sets an upstream one command later.
**The governed-surface section no longer claims this repo has no mechanical backstop.**
The paragraph asserted that nothing mechanical covers the governed surface here, that the
sibling repo's post-merge audit does not cover this repo, and — self-referentially — that
"a backstop this paragraph does not name is a backstop that does not exist". Measured
today, three of those claims are false: `.github/workflows/governed-surface-guard.yml` is
live and reports on every pull request, and the sibling audit has covered this repo since
objectstack#9619. The same file already named the guard 59 lines above, so the document
contradicted itself.
The replacement keeps what is still true (no CODEOWNERS, no hook, not yet a required
check), names the guard and its two legs — the `pull_request` leg deliberately exits 0, so
green does not mean ungoverned — records that it stays report-only until the ruleset
toggle is flipped, and points coverage at the script's own list instead of restating a
closed inventory that goes stale the next time a guard is added.
Net 0 lines in both files; the changeset carries empty frontmatter because no published
package's source changed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
…ause
One clause in the corrected backstop paragraph said the guard-versus-carve-out
divergence on published `skills/**` was awaiting the maintainer. It is not: the
ruling landed 2026-08-30 (director session, ruling batch 7, maintainer verbatim
「批 #7 同意」) taking Option A — published `skills/**` is governed, human merge,
with the 2026-08-26 md-versus-code split written in alongside it. The earlier
routing that described it as undecided was made from the card body alone and has
been withdrawn on the card.
The clause now states that the divergence is ruled, cites the ruling comment,
and says the guard's reading is the decided one — while noting the carve-out
text above has not yet been rewritten, so a reader must not act on it in the
meantime. Rewriting that text is the separate implementation card's job, not
this PR's.
Word-level edit inside the existing line: the paragraph stays one line, both
files keep their line totals (AGENTS.md 489, CLAUDE.md 51), and the carve-out
sentences remain byte-identical to origin/main.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:17
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit ba55fb5Aug 31, 2026
30 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6880-worktree-recipe-hardening branch August 31, 2026 07:30
os-sam pushed a commit that referenced this pull request Aug 31, 2026
Conflict resolution, one file, one hunk: the backstop paragraph.
While this branch sat in the merge queue, the maintainer landed #6976
(ba55fb5), which rewrote the same paragraph under the title "correct the
stale no-mechanical-backstop claim". That paragraph is authoritative and is
taken VERBATIM; this branch's competing rewrite of it is discarded in full,
not blended. Byte-checked: the whole paragraph up to its trailing caveat
clause is identical to origin/main (sha256 of the 1393-byte prefix matches),
including the CODEOWNERS sentence, the "尚未是 required context" sentence and
"在翻转之前,那条拒绝腿只报告、不阻止队列".
The branch's remaining edits auto-merged and are re-derived rather than
replayed: the list heading 四项 -> 五项, the new repo-root `skills/**` row
(`GOVERNED_SURFACES`'s `skills-catalog`), the docs/adr row's 上面三项 ->
上面四项 (verified: exactly 4 rows precede it), the ⚠️ block flipped to
"both skills trees are governed" while keeping `.agents/skills/` NOT governed,
and the inverted-scolding paragraph, which still taught the retired
".claude/-prefix" criterion on main and now records it as the past error.
One consequential edit beyond the branch: the maintainer's own trailing
caveat said the script's set and the list above "并不一致 ... 落地仍挂在
#6866 上,在它落地前 ⛔ 不要照上面那条豁免行事". This commit IS that landing,
so the clause is updated minimally to record the ruling as landed and the old
exemption as void. Nothing else in the paragraph is touched.
The ruling being implemented is the maintainer's 5th adjudication batch item
#7, Option A, recorded on #6866 comment 5469339478. No ruling is made here.
Verification (offline; both scripts import only node: builtins plus
scripts/invoked-as.mjs, so no install is in their closure):
node scripts/check-governed-queue-guard.mjs --self-test -> exit 0,
"OK check-governed-queue-guard self-test: 132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.md -> exit 3,
"⛔ GOVERNED — 1 of 1 path(s) are on a governed surface"
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
huangyiirene pushed a commit that referenced this pull request Aug 31, 2026
…diation text
`.claude/hooks/guard-main-checkout.sh` and `.claude/hooks/guard-main-checkout-bash.sh`
each end their block message with the worktree recipe to run instead, and both created
the branch with a plain `-b`. PR #6976 hardened the prescribed form in `CLAUDE.md` and
`AGENTS.md`; the hooks' copy was left behind — and it is the higher-leverage copy,
delivered at the exact moment an agent is about to act, so it is the one most likely to
be run verbatim.
The hazard is the one #6976 established: plain `-b` writes the new branch's upstream keys
(`branch.NAME.remote`, `branch.NAME.merge`) into the one `.git/config` that 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. Read as "the
worktree exists", the agent starts editing the shared primary checkout, which is the one
thing these two guards exist to prevent.
Additive, not a recipe rewrite: this repo's hooks already emitted the fetch-hardened base
(`git fetch origin main && … origin/main`, landed for ui#6208), so the missing flag was
the only surviving divergence from the prescribed form. One word added per file, net ±0
lines in both.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationpm:awaiting-maintainer

Projects

None yet

3 participants

@zhuangjianguo@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim by zhuangjianguo · Pull Request #6976 · objectstack-ai/objectui · GitHub
Skip to content

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim - #6976

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening
Aug 31, 2026
Merged

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim#6976
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening

Conversation

@zhuangjianguo

@zhuangjianguozhuangjianguo commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6880
Part of #6866 — its half 1 stays open (implementation tracked there) and is untouched here.

Two instruction-file corrections on the same governed face, folded into one PR because they
land in the same file and would otherwise be hard-serial.

1. The worktree recipe now specifies --no-track (the anchor card)

Byte-level insert into the two prescribed spellings, net 0 lines:

  • CLAUDE.md:16 — the fenced recipe.
  • AGENTS.md:234 — the same recipe inline.

(Placeholders written as words here; the files use angle-bracket placeholders.)

Plain -b writes the new branch's upstream keys — branch.NAME.remote and
branch.NAME.merge — into the one .git/config that 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 in the very first step of the recipe, and one the error text does not
name. Read as "the whole command failed", the retry hits branch already exists and reads
as a second, unrelated problem; read as "the worktree exists", the agent starts editing the
shared primary checkout — the single thing the worktree-first rule exists to prevent.

The measured basis is the anchor card's git 2.43.0 table, cited rather than re-derived:
--no-track removes the config write and still bases the worktree on origin/main;
explicit git pull origin main is unaffected (it uses the given refspec, never
branch.NAME.merge), and git push -u origin BRANCH — already the prescribed first push —
sets an upstream one command later.

This PR ate its own dogfood: its worktree was created with the hardened recipe.

Scope pin honoured (anchor triage, comment 5473464940)

p2 · pm:queue · domain:skills — scope pinned to the FLAG INSERT ONLY. [...] ⛔ The
prose extension (naming .git/config beside refs/stash / refs/remotes/*) is NOT in
scope here: its objectstack companion #13052-A is HELD for corpus audit objectstack#13597,
and the shared-namespace prose should be shaped by that audit in both repos at once.

No shared-namespace prose was extended. .git/config appears nowhere new in the
instruction text.

2. The "no mechanical backstop" paragraph, corrected in place (#6866 half 2)

Scope pin honoured (comment 5473466315)

Half 2 [...] is a plain correction and stays dispatchable now, independent of half 1:
name the guard, its report-only-vs-blocking state (#6596 still pm:awaiting-maintainer),
and its coverage, per the paragraph's own 「它会写在这里」 promise. Governed file ⇒ draft,
human merge.

The paragraph re-derived to AGENTS.md:433 (the card's :392 had drifted). Claim by claim,
measured on this branch's base:

claim in the paragraphverdict
"this repo has NO mechanical backstop, this paragraph is all there is"FALSE — the guard workflow is live
no CODEOWNERS (verified: the file does not exist)still TRUE — absent at every candidate path
no required check on the governed surfacestill TRUE — the ruleset toggle is pending on #6596
no hook on the governed surfacestill TRUE
no post-merge audit lists governed merges for anyoneFALSE
the sibling repo's audit "does not cover this repo"FALSE — it has covered four governed repos since objectstack#9619
a violation "succeeds silently, nobody is notified"FALSE — the guard reports on every PR
"a backstop this paragraph does not name is a backstop that does not exist"self-referential closure — removed

Two of those were not in the card and turned up while reading: the audit-coverage sentence
is false for the same reason the headline claim is, and it sits in the same paragraph, so
leaving it would have meant knowingly shipping a corrected paragraph that still asserts a
measured-false absence.

⭐ The sharpest corroboration is internal: the same file already named the guard 59 lines
above
, at AGENTS.md:372-376, as the workflow a tree enumeration missed. The document
contradicted itself, and the half asserting the absence was the half written to be trusted
absolutely.

The replacement keeps every claim that is still true, then names the guard
(.github/workflows/governed-surface-guard.yml, check Governed Surface Queue Guard,
predicate in scripts/check-governed-queue-guard.mjs), states both legs — the
pull_request leg deliberately exits 0, so green does not mean ungoverned, which is the
misread this paragraph would otherwise invite — records that the refusing merge_group leg
only reports until the ruleset toggle is flipped, and points coverage at the script's own
GOVERNED_SURFACES rather than restating a closed inventory that goes stale the next time a
guard is added. That last part is the paragraph's own promise being kept in a form that
cannot rot the same way.

The divergence clause (amended at 623b713)

The paragraph's closing clause originally described the guard-vs-carve-out divergence as an
open adjudication. That was stale on arrival: the maintainer had already ruled it on
2026-08-30 (第 5 场决裁批 #7, verbatim 「批 #7 同意」 — Option A, ui#6866 comment
5469339478). The clause now records the ruling itself — published skills/** is governed,
the guard's reading is the ruled one, implementation pending on #6866 — and forbids acting
on the carve-out until that lands. The carve-out sentences at AGENTS.md:419/:421 remain
byte-identical in this PR; their Option-A rewrite is #6866's follow-up implementation,
deliberately not folded in here.

Not in this PR

Validation

Round 1 at 64d6421, amend re-run at 623b713; exit codes captured before any pipe.

checkexitverdict line
check:control-bytes0✅ check-control-bytes: OK (scanned 5804 tracked text file(s); skipped 85 binary).
check:doc-fences0✅ check:doc-fences — every TypeScript block in 224 document(s) is fenced ts/tsx/typescript
check:governed-queue-guard0OK check-governed-queue-guard self-test: 132 cases pass
check-changeset-presence.mjs0✅ No source of a released package changed in this range, so no changeset is owed.
check-doc-links.mjs0Links are valid across 17 scan roots.
all 4 hook self-tests0121 passed, 0 failed · 41 passed, 0 failed · 36 passed, 0 failed

Anchored greps with positive controls (after the amend): --no-track1 in each file;
本仓没有任何机械兜底0; 本段没点名的兜底工具0; 这一分歧在 #6866 待维护者裁决0;
批 #71; controls — 受管面 in AGENTS.md7; PreToolUse5;
guard-shared-stash.sh in CLAUDE.md1. Line totals unchanged: CLAUDE.md 51,
AGENTS.md 489 — net 0 lines in both.

The guard, run against this PR's own file list, agrees with what the new paragraph says
about it:

⛔ GOVERNED — 2 of 3 path(s) are on a governed surface:
AGENTS.md x1 — the repo-root agent instruction file
CLAUDE.md x1 — the repo-root Claude instruction file
⛔ Do not flip it ready, enqueue it, or arm auto-merge. Park it as a DRAFT and leave the
merge to the maintainer; a human merge IS the review record for a governed surface.

Landing

Governed surface ⇒ draft, human merge (pm:awaiting-maintainer per 批 #7's execution
note). ⛔ Not flipped ready, not enqueued, no auto-merge. The changeset carries empty
frontmatter — this repo's measured form for a non-publishing change (precedent:
.changeset/6208-worktree-recipe-fetch-base.md, the same change class).

Generated by Claude Code

…o-backstop claim
Two instruction-file corrections on the same governed face.
**The prescribed worktree recipe now specifies `--no-track`** (`CLAUDE.md`, `AGENTS.md`).
Plain `-b` writes the new branch's upstream keys — `branch.NAME.remote` and
`branch.NAME.merge` — into the one `.git/config` that 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 in the very first step of the recipe, and one the error text does
not name. Read as "the whole command failed", the retry hits `branch already exists` and
reads as a second, unrelated problem; read as "the worktree exists", the agent starts
editing the shared primary checkout — the one thing the worktree-first rule exists to
prevent.
Measured on git 2.43.0: `--no-track` removes the config write and still bases the worktree
on `origin/main`. Explicit `git pull origin main` is unaffected (it uses the given refspec,
never `branch.NAME.merge`), and `git push -u origin BRANCH` — already the prescribed first
push — sets an upstream one command later.
**The governed-surface section no longer claims this repo has no mechanical backstop.**
The paragraph asserted that nothing mechanical covers the governed surface here, that the
sibling repo's post-merge audit does not cover this repo, and — self-referentially — that
"a backstop this paragraph does not name is a backstop that does not exist". Measured
today, three of those claims are false: `.github/workflows/governed-surface-guard.yml` is
live and reports on every pull request, and the sibling audit has covered this repo since
objectstack#9619. The same file already named the guard 59 lines above, so the document
contradicted itself.
The replacement keeps what is still true (no CODEOWNERS, no hook, not yet a required
check), names the guard and its two legs — the `pull_request` leg deliberately exits 0, so
green does not mean ungoverned — records that it stays report-only until the ruleset
toggle is flipped, and points coverage at the script's own list instead of restating a
closed inventory that goes stale the next time a guard is added.
Net 0 lines in both files; the changeset carries empty frontmatter because no published
package's source changed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
…ause
One clause in the corrected backstop paragraph said the guard-versus-carve-out
divergence on published `skills/**` was awaiting the maintainer. It is not: the
ruling landed 2026-08-30 (director session, ruling batch 7, maintainer verbatim
「批 #7 同意」) taking Option A — published `skills/**` is governed, human merge,
with the 2026-08-26 md-versus-code split written in alongside it. The earlier
routing that described it as undecided was made from the card body alone and has
been withdrawn on the card.
The clause now states that the divergence is ruled, cites the ruling comment,
and says the guard's reading is the decided one — while noting the carve-out
text above has not yet been rewritten, so a reader must not act on it in the
meantime. Rewriting that text is the separate implementation card's job, not
this PR's.
Word-level edit inside the existing line: the paragraph stays one line, both
files keep their line totals (AGENTS.md 489, CLAUDE.md 51), and the carve-out
sentences remain byte-identical to origin/main.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:17
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit ba55fb5Aug 31, 2026
30 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6880-worktree-recipe-hardening branch August 31, 2026 07:30
os-sam pushed a commit that referenced this pull request Aug 31, 2026
Conflict resolution, one file, one hunk: the backstop paragraph.
While this branch sat in the merge queue, the maintainer landed #6976
(ba55fb5), which rewrote the same paragraph under the title "correct the
stale no-mechanical-backstop claim". That paragraph is authoritative and is
taken VERBATIM; this branch's competing rewrite of it is discarded in full,
not blended. Byte-checked: the whole paragraph up to its trailing caveat
clause is identical to origin/main (sha256 of the 1393-byte prefix matches),
including the CODEOWNERS sentence, the "尚未是 required context" sentence and
"在翻转之前,那条拒绝腿只报告、不阻止队列".
The branch's remaining edits auto-merged and are re-derived rather than
replayed: the list heading 四项 -> 五项, the new repo-root `skills/**` row
(`GOVERNED_SURFACES`'s `skills-catalog`), the docs/adr row's 上面三项 ->
上面四项 (verified: exactly 4 rows precede it), the ⚠️ block flipped to
"both skills trees are governed" while keeping `.agents/skills/` NOT governed,
and the inverted-scolding paragraph, which still taught the retired
".claude/-prefix" criterion on main and now records it as the past error.
One consequential edit beyond the branch: the maintainer's own trailing
caveat said the script's set and the list above "并不一致 ... 落地仍挂在
#6866 上,在它落地前 ⛔ 不要照上面那条豁免行事". This commit IS that landing,
so the clause is updated minimally to record the ruling as landed and the old
exemption as void. Nothing else in the paragraph is touched.
The ruling being implemented is the maintainer's 5th adjudication batch item
#7, Option A, recorded on #6866 comment 5469339478. No ruling is made here.
Verification (offline; both scripts import only node: builtins plus
scripts/invoked-as.mjs, so no install is in their closure):
node scripts/check-governed-queue-guard.mjs --self-test -> exit 0,
"OK check-governed-queue-guard self-test: 132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.md -> exit 3,
"⛔ GOVERNED — 1 of 1 path(s) are on a governed surface"
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
huangyiirene pushed a commit that referenced this pull request Aug 31, 2026
…diation text
`.claude/hooks/guard-main-checkout.sh` and `.claude/hooks/guard-main-checkout-bash.sh`
each end their block message with the worktree recipe to run instead, and both created
the branch with a plain `-b`. PR #6976 hardened the prescribed form in `CLAUDE.md` and
`AGENTS.md`; the hooks' copy was left behind — and it is the higher-leverage copy,
delivered at the exact moment an agent is about to act, so it is the one most likely to
be run verbatim.
The hazard is the one #6976 established: plain `-b` writes the new branch's upstream keys
(`branch.NAME.remote`, `branch.NAME.merge`) into the one `.git/config` that 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. Read as "the
worktree exists", the agent starts editing the shared primary checkout, which is the one
thing these two guards exist to prevent.
Additive, not a recipe rewrite: this repo's hooks already emitted the fetch-hardened base
(`git fetch origin main && … origin/main`, landed for ui#6208), so the missing flag was
the only surviving divergence from the prescribed form. One word added per file, net ±0
lines in both.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationpm:awaiting-maintainer

Projects

None yet

3 participants

@zhuangjianguo@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim by zhuangjianguo · Pull Request #6976 · objectstack-ai/objectui · GitHub
Skip to content

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim - #6976

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening
Aug 31, 2026
Merged

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim#6976
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening

Conversation

@zhuangjianguo

@zhuangjianguozhuangjianguo commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6880
Part of #6866 — its half 1 stays open (implementation tracked there) and is untouched here.

Two instruction-file corrections on the same governed face, folded into one PR because they
land in the same file and would otherwise be hard-serial.

1. The worktree recipe now specifies --no-track (the anchor card)

Byte-level insert into the two prescribed spellings, net 0 lines:

  • CLAUDE.md:16 — the fenced recipe.
  • AGENTS.md:234 — the same recipe inline.

(Placeholders written as words here; the files use angle-bracket placeholders.)

Plain -b writes the new branch's upstream keys — branch.NAME.remote and
branch.NAME.merge — into the one .git/config that 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 in the very first step of the recipe, and one the error text does not
name. Read as "the whole command failed", the retry hits branch already exists and reads
as a second, unrelated problem; read as "the worktree exists", the agent starts editing the
shared primary checkout — the single thing the worktree-first rule exists to prevent.

The measured basis is the anchor card's git 2.43.0 table, cited rather than re-derived:
--no-track removes the config write and still bases the worktree on origin/main;
explicit git pull origin main is unaffected (it uses the given refspec, never
branch.NAME.merge), and git push -u origin BRANCH — already the prescribed first push —
sets an upstream one command later.

This PR ate its own dogfood: its worktree was created with the hardened recipe.

Scope pin honoured (anchor triage, comment 5473464940)

p2 · pm:queue · domain:skills — scope pinned to the FLAG INSERT ONLY. [...] ⛔ The
prose extension (naming .git/config beside refs/stash / refs/remotes/*) is NOT in
scope here: its objectstack companion #13052-A is HELD for corpus audit objectstack#13597,
and the shared-namespace prose should be shaped by that audit in both repos at once.

No shared-namespace prose was extended. .git/config appears nowhere new in the
instruction text.

2. The "no mechanical backstop" paragraph, corrected in place (#6866 half 2)

Scope pin honoured (comment 5473466315)

Half 2 [...] is a plain correction and stays dispatchable now, independent of half 1:
name the guard, its report-only-vs-blocking state (#6596 still pm:awaiting-maintainer),
and its coverage, per the paragraph's own 「它会写在这里」 promise. Governed file ⇒ draft,
human merge.

The paragraph re-derived to AGENTS.md:433 (the card's :392 had drifted). Claim by claim,
measured on this branch's base:

claim in the paragraphverdict
"this repo has NO mechanical backstop, this paragraph is all there is"FALSE — the guard workflow is live
no CODEOWNERS (verified: the file does not exist)still TRUE — absent at every candidate path
no required check on the governed surfacestill TRUE — the ruleset toggle is pending on #6596
no hook on the governed surfacestill TRUE
no post-merge audit lists governed merges for anyoneFALSE
the sibling repo's audit "does not cover this repo"FALSE — it has covered four governed repos since objectstack#9619
a violation "succeeds silently, nobody is notified"FALSE — the guard reports on every PR
"a backstop this paragraph does not name is a backstop that does not exist"self-referential closure — removed

Two of those were not in the card and turned up while reading: the audit-coverage sentence
is false for the same reason the headline claim is, and it sits in the same paragraph, so
leaving it would have meant knowingly shipping a corrected paragraph that still asserts a
measured-false absence.

⭐ The sharpest corroboration is internal: the same file already named the guard 59 lines
above
, at AGENTS.md:372-376, as the workflow a tree enumeration missed. The document
contradicted itself, and the half asserting the absence was the half written to be trusted
absolutely.

The replacement keeps every claim that is still true, then names the guard
(.github/workflows/governed-surface-guard.yml, check Governed Surface Queue Guard,
predicate in scripts/check-governed-queue-guard.mjs), states both legs — the
pull_request leg deliberately exits 0, so green does not mean ungoverned, which is the
misread this paragraph would otherwise invite — records that the refusing merge_group leg
only reports until the ruleset toggle is flipped, and points coverage at the script's own
GOVERNED_SURFACES rather than restating a closed inventory that goes stale the next time a
guard is added. That last part is the paragraph's own promise being kept in a form that
cannot rot the same way.

The divergence clause (amended at 623b713)

The paragraph's closing clause originally described the guard-vs-carve-out divergence as an
open adjudication. That was stale on arrival: the maintainer had already ruled it on
2026-08-30 (第 5 场决裁批 #7, verbatim 「批 #7 同意」 — Option A, ui#6866 comment
5469339478). The clause now records the ruling itself — published skills/** is governed,
the guard's reading is the ruled one, implementation pending on #6866 — and forbids acting
on the carve-out until that lands. The carve-out sentences at AGENTS.md:419/:421 remain
byte-identical in this PR; their Option-A rewrite is #6866's follow-up implementation,
deliberately not folded in here.

Not in this PR

Validation

Round 1 at 64d6421, amend re-run at 623b713; exit codes captured before any pipe.

checkexitverdict line
check:control-bytes0✅ check-control-bytes: OK (scanned 5804 tracked text file(s); skipped 85 binary).
check:doc-fences0✅ check:doc-fences — every TypeScript block in 224 document(s) is fenced ts/tsx/typescript
check:governed-queue-guard0OK check-governed-queue-guard self-test: 132 cases pass
check-changeset-presence.mjs0✅ No source of a released package changed in this range, so no changeset is owed.
check-doc-links.mjs0Links are valid across 17 scan roots.
all 4 hook self-tests0121 passed, 0 failed · 41 passed, 0 failed · 36 passed, 0 failed

Anchored greps with positive controls (after the amend): --no-track1 in each file;
本仓没有任何机械兜底0; 本段没点名的兜底工具0; 这一分歧在 #6866 待维护者裁决0;
批 #71; controls — 受管面 in AGENTS.md7; PreToolUse5;
guard-shared-stash.sh in CLAUDE.md1. Line totals unchanged: CLAUDE.md 51,
AGENTS.md 489 — net 0 lines in both.

The guard, run against this PR's own file list, agrees with what the new paragraph says
about it:

⛔ GOVERNED — 2 of 3 path(s) are on a governed surface:
AGENTS.md x1 — the repo-root agent instruction file
CLAUDE.md x1 — the repo-root Claude instruction file
⛔ Do not flip it ready, enqueue it, or arm auto-merge. Park it as a DRAFT and leave the
merge to the maintainer; a human merge IS the review record for a governed surface.

Landing

Governed surface ⇒ draft, human merge (pm:awaiting-maintainer per 批 #7's execution
note). ⛔ Not flipped ready, not enqueued, no auto-merge. The changeset carries empty
frontmatter — this repo's measured form for a non-publishing change (precedent:
.changeset/6208-worktree-recipe-fetch-base.md, the same change class).

Generated by Claude Code

…o-backstop claim
Two instruction-file corrections on the same governed face.
**The prescribed worktree recipe now specifies `--no-track`** (`CLAUDE.md`, `AGENTS.md`).
Plain `-b` writes the new branch's upstream keys — `branch.NAME.remote` and
`branch.NAME.merge` — into the one `.git/config` that 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 in the very first step of the recipe, and one the error text does
not name. Read as "the whole command failed", the retry hits `branch already exists` and
reads as a second, unrelated problem; read as "the worktree exists", the agent starts
editing the shared primary checkout — the one thing the worktree-first rule exists to
prevent.
Measured on git 2.43.0: `--no-track` removes the config write and still bases the worktree
on `origin/main`. Explicit `git pull origin main` is unaffected (it uses the given refspec,
never `branch.NAME.merge`), and `git push -u origin BRANCH` — already the prescribed first
push — sets an upstream one command later.
**The governed-surface section no longer claims this repo has no mechanical backstop.**
The paragraph asserted that nothing mechanical covers the governed surface here, that the
sibling repo's post-merge audit does not cover this repo, and — self-referentially — that
"a backstop this paragraph does not name is a backstop that does not exist". Measured
today, three of those claims are false: `.github/workflows/governed-surface-guard.yml` is
live and reports on every pull request, and the sibling audit has covered this repo since
objectstack#9619. The same file already named the guard 59 lines above, so the document
contradicted itself.
The replacement keeps what is still true (no CODEOWNERS, no hook, not yet a required
check), names the guard and its two legs — the `pull_request` leg deliberately exits 0, so
green does not mean ungoverned — records that it stays report-only until the ruleset
toggle is flipped, and points coverage at the script's own list instead of restating a
closed inventory that goes stale the next time a guard is added.
Net 0 lines in both files; the changeset carries empty frontmatter because no published
package's source changed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
…ause
One clause in the corrected backstop paragraph said the guard-versus-carve-out
divergence on published `skills/**` was awaiting the maintainer. It is not: the
ruling landed 2026-08-30 (director session, ruling batch 7, maintainer verbatim
「批 #7 同意」) taking Option A — published `skills/**` is governed, human merge,
with the 2026-08-26 md-versus-code split written in alongside it. The earlier
routing that described it as undecided was made from the card body alone and has
been withdrawn on the card.
The clause now states that the divergence is ruled, cites the ruling comment,
and says the guard's reading is the decided one — while noting the carve-out
text above has not yet been rewritten, so a reader must not act on it in the
meantime. Rewriting that text is the separate implementation card's job, not
this PR's.
Word-level edit inside the existing line: the paragraph stays one line, both
files keep their line totals (AGENTS.md 489, CLAUDE.md 51), and the carve-out
sentences remain byte-identical to origin/main.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:17
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit ba55fb5Aug 31, 2026
30 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6880-worktree-recipe-hardening branch August 31, 2026 07:30
os-sam pushed a commit that referenced this pull request Aug 31, 2026
Conflict resolution, one file, one hunk: the backstop paragraph.
While this branch sat in the merge queue, the maintainer landed #6976
(ba55fb5), which rewrote the same paragraph under the title "correct the
stale no-mechanical-backstop claim". That paragraph is authoritative and is
taken VERBATIM; this branch's competing rewrite of it is discarded in full,
not blended. Byte-checked: the whole paragraph up to its trailing caveat
clause is identical to origin/main (sha256 of the 1393-byte prefix matches),
including the CODEOWNERS sentence, the "尚未是 required context" sentence and
"在翻转之前,那条拒绝腿只报告、不阻止队列".
The branch's remaining edits auto-merged and are re-derived rather than
replayed: the list heading 四项 -> 五项, the new repo-root `skills/**` row
(`GOVERNED_SURFACES`'s `skills-catalog`), the docs/adr row's 上面三项 ->
上面四项 (verified: exactly 4 rows precede it), the ⚠️ block flipped to
"both skills trees are governed" while keeping `.agents/skills/` NOT governed,
and the inverted-scolding paragraph, which still taught the retired
".claude/-prefix" criterion on main and now records it as the past error.
One consequential edit beyond the branch: the maintainer's own trailing
caveat said the script's set and the list above "并不一致 ... 落地仍挂在
#6866 上,在它落地前 ⛔ 不要照上面那条豁免行事". This commit IS that landing,
so the clause is updated minimally to record the ruling as landed and the old
exemption as void. Nothing else in the paragraph is touched.
The ruling being implemented is the maintainer's 5th adjudication batch item
#7, Option A, recorded on #6866 comment 5469339478. No ruling is made here.
Verification (offline; both scripts import only node: builtins plus
scripts/invoked-as.mjs, so no install is in their closure):
node scripts/check-governed-queue-guard.mjs --self-test -> exit 0,
"OK check-governed-queue-guard self-test: 132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.md -> exit 3,
"⛔ GOVERNED — 1 of 1 path(s) are on a governed surface"
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
huangyiirene pushed a commit that referenced this pull request Aug 31, 2026
…diation text
`.claude/hooks/guard-main-checkout.sh` and `.claude/hooks/guard-main-checkout-bash.sh`
each end their block message with the worktree recipe to run instead, and both created
the branch with a plain `-b`. PR #6976 hardened the prescribed form in `CLAUDE.md` and
`AGENTS.md`; the hooks' copy was left behind — and it is the higher-leverage copy,
delivered at the exact moment an agent is about to act, so it is the one most likely to
be run verbatim.
The hazard is the one #6976 established: plain `-b` writes the new branch's upstream keys
(`branch.NAME.remote`, `branch.NAME.merge`) into the one `.git/config` that 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. Read as "the
worktree exists", the agent starts editing the shared primary checkout, which is the one
thing these two guards exist to prevent.
Additive, not a recipe rewrite: this repo's hooks already emitted the fetch-hardened base
(`git fetch origin main && … origin/main`, landed for ui#6208), so the missing flag was
the only surviving divergence from the prescribed form. One word added per file, net ±0
lines in both.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationpm:awaiting-maintainer

Projects

None yet

3 participants

@zhuangjianguo@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim by zhuangjianguo · Pull Request #6976 · objectstack-ai/objectui · GitHub
Skip to content

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim - #6976

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening
Aug 31, 2026
Merged

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim#6976
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening

Conversation

@zhuangjianguo

@zhuangjianguozhuangjianguo commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6880
Part of #6866 — its half 1 stays open (implementation tracked there) and is untouched here.

Two instruction-file corrections on the same governed face, folded into one PR because they
land in the same file and would otherwise be hard-serial.

1. The worktree recipe now specifies --no-track (the anchor card)

Byte-level insert into the two prescribed spellings, net 0 lines:

  • CLAUDE.md:16 — the fenced recipe.
  • AGENTS.md:234 — the same recipe inline.

(Placeholders written as words here; the files use angle-bracket placeholders.)

Plain -b writes the new branch's upstream keys — branch.NAME.remote and
branch.NAME.merge — into the one .git/config that 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 in the very first step of the recipe, and one the error text does not
name. Read as "the whole command failed", the retry hits branch already exists and reads
as a second, unrelated problem; read as "the worktree exists", the agent starts editing the
shared primary checkout — the single thing the worktree-first rule exists to prevent.

The measured basis is the anchor card's git 2.43.0 table, cited rather than re-derived:
--no-track removes the config write and still bases the worktree on origin/main;
explicit git pull origin main is unaffected (it uses the given refspec, never
branch.NAME.merge), and git push -u origin BRANCH — already the prescribed first push —
sets an upstream one command later.

This PR ate its own dogfood: its worktree was created with the hardened recipe.

Scope pin honoured (anchor triage, comment 5473464940)

p2 · pm:queue · domain:skills — scope pinned to the FLAG INSERT ONLY. [...] ⛔ The
prose extension (naming .git/config beside refs/stash / refs/remotes/*) is NOT in
scope here: its objectstack companion #13052-A is HELD for corpus audit objectstack#13597,
and the shared-namespace prose should be shaped by that audit in both repos at once.

No shared-namespace prose was extended. .git/config appears nowhere new in the
instruction text.

2. The "no mechanical backstop" paragraph, corrected in place (#6866 half 2)

Scope pin honoured (comment 5473466315)

Half 2 [...] is a plain correction and stays dispatchable now, independent of half 1:
name the guard, its report-only-vs-blocking state (#6596 still pm:awaiting-maintainer),
and its coverage, per the paragraph's own 「它会写在这里」 promise. Governed file ⇒ draft,
human merge.

The paragraph re-derived to AGENTS.md:433 (the card's :392 had drifted). Claim by claim,
measured on this branch's base:

claim in the paragraphverdict
"this repo has NO mechanical backstop, this paragraph is all there is"FALSE — the guard workflow is live
no CODEOWNERS (verified: the file does not exist)still TRUE — absent at every candidate path
no required check on the governed surfacestill TRUE — the ruleset toggle is pending on #6596
no hook on the governed surfacestill TRUE
no post-merge audit lists governed merges for anyoneFALSE
the sibling repo's audit "does not cover this repo"FALSE — it has covered four governed repos since objectstack#9619
a violation "succeeds silently, nobody is notified"FALSE — the guard reports on every PR
"a backstop this paragraph does not name is a backstop that does not exist"self-referential closure — removed

Two of those were not in the card and turned up while reading: the audit-coverage sentence
is false for the same reason the headline claim is, and it sits in the same paragraph, so
leaving it would have meant knowingly shipping a corrected paragraph that still asserts a
measured-false absence.

⭐ The sharpest corroboration is internal: the same file already named the guard 59 lines
above
, at AGENTS.md:372-376, as the workflow a tree enumeration missed. The document
contradicted itself, and the half asserting the absence was the half written to be trusted
absolutely.

The replacement keeps every claim that is still true, then names the guard
(.github/workflows/governed-surface-guard.yml, check Governed Surface Queue Guard,
predicate in scripts/check-governed-queue-guard.mjs), states both legs — the
pull_request leg deliberately exits 0, so green does not mean ungoverned, which is the
misread this paragraph would otherwise invite — records that the refusing merge_group leg
only reports until the ruleset toggle is flipped, and points coverage at the script's own
GOVERNED_SURFACES rather than restating a closed inventory that goes stale the next time a
guard is added. That last part is the paragraph's own promise being kept in a form that
cannot rot the same way.

The divergence clause (amended at 623b713)

The paragraph's closing clause originally described the guard-vs-carve-out divergence as an
open adjudication. That was stale on arrival: the maintainer had already ruled it on
2026-08-30 (第 5 场决裁批 #7, verbatim 「批 #7 同意」 — Option A, ui#6866 comment
5469339478). The clause now records the ruling itself — published skills/** is governed,
the guard's reading is the ruled one, implementation pending on #6866 — and forbids acting
on the carve-out until that lands. The carve-out sentences at AGENTS.md:419/:421 remain
byte-identical in this PR; their Option-A rewrite is #6866's follow-up implementation,
deliberately not folded in here.

Not in this PR

Validation

Round 1 at 64d6421, amend re-run at 623b713; exit codes captured before any pipe.

checkexitverdict line
check:control-bytes0✅ check-control-bytes: OK (scanned 5804 tracked text file(s); skipped 85 binary).
check:doc-fences0✅ check:doc-fences — every TypeScript block in 224 document(s) is fenced ts/tsx/typescript
check:governed-queue-guard0OK check-governed-queue-guard self-test: 132 cases pass
check-changeset-presence.mjs0✅ No source of a released package changed in this range, so no changeset is owed.
check-doc-links.mjs0Links are valid across 17 scan roots.
all 4 hook self-tests0121 passed, 0 failed · 41 passed, 0 failed · 36 passed, 0 failed

Anchored greps with positive controls (after the amend): --no-track1 in each file;
本仓没有任何机械兜底0; 本段没点名的兜底工具0; 这一分歧在 #6866 待维护者裁决0;
批 #71; controls — 受管面 in AGENTS.md7; PreToolUse5;
guard-shared-stash.sh in CLAUDE.md1. Line totals unchanged: CLAUDE.md 51,
AGENTS.md 489 — net 0 lines in both.

The guard, run against this PR's own file list, agrees with what the new paragraph says
about it:

⛔ GOVERNED — 2 of 3 path(s) are on a governed surface:
AGENTS.md x1 — the repo-root agent instruction file
CLAUDE.md x1 — the repo-root Claude instruction file
⛔ Do not flip it ready, enqueue it, or arm auto-merge. Park it as a DRAFT and leave the
merge to the maintainer; a human merge IS the review record for a governed surface.

Landing

Governed surface ⇒ draft, human merge (pm:awaiting-maintainer per 批 #7's execution
note). ⛔ Not flipped ready, not enqueued, no auto-merge. The changeset carries empty
frontmatter — this repo's measured form for a non-publishing change (precedent:
.changeset/6208-worktree-recipe-fetch-base.md, the same change class).

Generated by Claude Code

…o-backstop claim
Two instruction-file corrections on the same governed face.
**The prescribed worktree recipe now specifies `--no-track`** (`CLAUDE.md`, `AGENTS.md`).
Plain `-b` writes the new branch's upstream keys — `branch.NAME.remote` and
`branch.NAME.merge` — into the one `.git/config` that 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 in the very first step of the recipe, and one the error text does
not name. Read as "the whole command failed", the retry hits `branch already exists` and
reads as a second, unrelated problem; read as "the worktree exists", the agent starts
editing the shared primary checkout — the one thing the worktree-first rule exists to
prevent.
Measured on git 2.43.0: `--no-track` removes the config write and still bases the worktree
on `origin/main`. Explicit `git pull origin main` is unaffected (it uses the given refspec,
never `branch.NAME.merge`), and `git push -u origin BRANCH` — already the prescribed first
push — sets an upstream one command later.
**The governed-surface section no longer claims this repo has no mechanical backstop.**
The paragraph asserted that nothing mechanical covers the governed surface here, that the
sibling repo's post-merge audit does not cover this repo, and — self-referentially — that
"a backstop this paragraph does not name is a backstop that does not exist". Measured
today, three of those claims are false: `.github/workflows/governed-surface-guard.yml` is
live and reports on every pull request, and the sibling audit has covered this repo since
objectstack#9619. The same file already named the guard 59 lines above, so the document
contradicted itself.
The replacement keeps what is still true (no CODEOWNERS, no hook, not yet a required
check), names the guard and its two legs — the `pull_request` leg deliberately exits 0, so
green does not mean ungoverned — records that it stays report-only until the ruleset
toggle is flipped, and points coverage at the script's own list instead of restating a
closed inventory that goes stale the next time a guard is added.
Net 0 lines in both files; the changeset carries empty frontmatter because no published
package's source changed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
…ause
One clause in the corrected backstop paragraph said the guard-versus-carve-out
divergence on published `skills/**` was awaiting the maintainer. It is not: the
ruling landed 2026-08-30 (director session, ruling batch 7, maintainer verbatim
「批 #7 同意」) taking Option A — published `skills/**` is governed, human merge,
with the 2026-08-26 md-versus-code split written in alongside it. The earlier
routing that described it as undecided was made from the card body alone and has
been withdrawn on the card.
The clause now states that the divergence is ruled, cites the ruling comment,
and says the guard's reading is the decided one — while noting the carve-out
text above has not yet been rewritten, so a reader must not act on it in the
meantime. Rewriting that text is the separate implementation card's job, not
this PR's.
Word-level edit inside the existing line: the paragraph stays one line, both
files keep their line totals (AGENTS.md 489, CLAUDE.md 51), and the carve-out
sentences remain byte-identical to origin/main.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:17
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit ba55fb5Aug 31, 2026
30 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6880-worktree-recipe-hardening branch August 31, 2026 07:30
os-sam pushed a commit that referenced this pull request Aug 31, 2026
Conflict resolution, one file, one hunk: the backstop paragraph.
While this branch sat in the merge queue, the maintainer landed #6976
(ba55fb5), which rewrote the same paragraph under the title "correct the
stale no-mechanical-backstop claim". That paragraph is authoritative and is
taken VERBATIM; this branch's competing rewrite of it is discarded in full,
not blended. Byte-checked: the whole paragraph up to its trailing caveat
clause is identical to origin/main (sha256 of the 1393-byte prefix matches),
including the CODEOWNERS sentence, the "尚未是 required context" sentence and
"在翻转之前,那条拒绝腿只报告、不阻止队列".
The branch's remaining edits auto-merged and are re-derived rather than
replayed: the list heading 四项 -> 五项, the new repo-root `skills/**` row
(`GOVERNED_SURFACES`'s `skills-catalog`), the docs/adr row's 上面三项 ->
上面四项 (verified: exactly 4 rows precede it), the ⚠️ block flipped to
"both skills trees are governed" while keeping `.agents/skills/` NOT governed,
and the inverted-scolding paragraph, which still taught the retired
".claude/-prefix" criterion on main and now records it as the past error.
One consequential edit beyond the branch: the maintainer's own trailing
caveat said the script's set and the list above "并不一致 ... 落地仍挂在
#6866 上,在它落地前 ⛔ 不要照上面那条豁免行事". This commit IS that landing,
so the clause is updated minimally to record the ruling as landed and the old
exemption as void. Nothing else in the paragraph is touched.
The ruling being implemented is the maintainer's 5th adjudication batch item
#7, Option A, recorded on #6866 comment 5469339478. No ruling is made here.
Verification (offline; both scripts import only node: builtins plus
scripts/invoked-as.mjs, so no install is in their closure):
node scripts/check-governed-queue-guard.mjs --self-test -> exit 0,
"OK check-governed-queue-guard self-test: 132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.md -> exit 3,
"⛔ GOVERNED — 1 of 1 path(s) are on a governed surface"
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
huangyiirene pushed a commit that referenced this pull request Aug 31, 2026
…diation text
`.claude/hooks/guard-main-checkout.sh` and `.claude/hooks/guard-main-checkout-bash.sh`
each end their block message with the worktree recipe to run instead, and both created
the branch with a plain `-b`. PR #6976 hardened the prescribed form in `CLAUDE.md` and
`AGENTS.md`; the hooks' copy was left behind — and it is the higher-leverage copy,
delivered at the exact moment an agent is about to act, so it is the one most likely to
be run verbatim.
The hazard is the one #6976 established: plain `-b` writes the new branch's upstream keys
(`branch.NAME.remote`, `branch.NAME.merge`) into the one `.git/config` that 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. Read as "the
worktree exists", the agent starts editing the shared primary checkout, which is the one
thing these two guards exist to prevent.
Additive, not a recipe rewrite: this repo's hooks already emitted the fetch-hardened base
(`git fetch origin main && … origin/main`, landed for ui#6208), so the missing flag was
the only surviving divergence from the prescribed form. One word added per file, net ±0
lines in both.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationpm:awaiting-maintainer

Projects

None yet

3 participants

@zhuangjianguo@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim by zhuangjianguo · Pull Request #6976 · objectstack-ai/objectui · GitHub
Skip to content

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim - #6976

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening
Aug 31, 2026
Merged

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim#6976
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening

Conversation

@zhuangjianguo

@zhuangjianguozhuangjianguo commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6880
Part of #6866 — its half 1 stays open (implementation tracked there) and is untouched here.

Two instruction-file corrections on the same governed face, folded into one PR because they
land in the same file and would otherwise be hard-serial.

1. The worktree recipe now specifies --no-track (the anchor card)

Byte-level insert into the two prescribed spellings, net 0 lines:

  • CLAUDE.md:16 — the fenced recipe.
  • AGENTS.md:234 — the same recipe inline.

(Placeholders written as words here; the files use angle-bracket placeholders.)

Plain -b writes the new branch's upstream keys — branch.NAME.remote and
branch.NAME.merge — into the one .git/config that 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 in the very first step of the recipe, and one the error text does not
name. Read as "the whole command failed", the retry hits branch already exists and reads
as a second, unrelated problem; read as "the worktree exists", the agent starts editing the
shared primary checkout — the single thing the worktree-first rule exists to prevent.

The measured basis is the anchor card's git 2.43.0 table, cited rather than re-derived:
--no-track removes the config write and still bases the worktree on origin/main;
explicit git pull origin main is unaffected (it uses the given refspec, never
branch.NAME.merge), and git push -u origin BRANCH — already the prescribed first push —
sets an upstream one command later.

This PR ate its own dogfood: its worktree was created with the hardened recipe.

Scope pin honoured (anchor triage, comment 5473464940)

p2 · pm:queue · domain:skills — scope pinned to the FLAG INSERT ONLY. [...] ⛔ The
prose extension (naming .git/config beside refs/stash / refs/remotes/*) is NOT in
scope here: its objectstack companion #13052-A is HELD for corpus audit objectstack#13597,
and the shared-namespace prose should be shaped by that audit in both repos at once.

No shared-namespace prose was extended. .git/config appears nowhere new in the
instruction text.

2. The "no mechanical backstop" paragraph, corrected in place (#6866 half 2)

Scope pin honoured (comment 5473466315)

Half 2 [...] is a plain correction and stays dispatchable now, independent of half 1:
name the guard, its report-only-vs-blocking state (#6596 still pm:awaiting-maintainer),
and its coverage, per the paragraph's own 「它会写在这里」 promise. Governed file ⇒ draft,
human merge.

The paragraph re-derived to AGENTS.md:433 (the card's :392 had drifted). Claim by claim,
measured on this branch's base:

claim in the paragraphverdict
"this repo has NO mechanical backstop, this paragraph is all there is"FALSE — the guard workflow is live
no CODEOWNERS (verified: the file does not exist)still TRUE — absent at every candidate path
no required check on the governed surfacestill TRUE — the ruleset toggle is pending on #6596
no hook on the governed surfacestill TRUE
no post-merge audit lists governed merges for anyoneFALSE
the sibling repo's audit "does not cover this repo"FALSE — it has covered four governed repos since objectstack#9619
a violation "succeeds silently, nobody is notified"FALSE — the guard reports on every PR
"a backstop this paragraph does not name is a backstop that does not exist"self-referential closure — removed

Two of those were not in the card and turned up while reading: the audit-coverage sentence
is false for the same reason the headline claim is, and it sits in the same paragraph, so
leaving it would have meant knowingly shipping a corrected paragraph that still asserts a
measured-false absence.

⭐ The sharpest corroboration is internal: the same file already named the guard 59 lines
above
, at AGENTS.md:372-376, as the workflow a tree enumeration missed. The document
contradicted itself, and the half asserting the absence was the half written to be trusted
absolutely.

The replacement keeps every claim that is still true, then names the guard
(.github/workflows/governed-surface-guard.yml, check Governed Surface Queue Guard,
predicate in scripts/check-governed-queue-guard.mjs), states both legs — the
pull_request leg deliberately exits 0, so green does not mean ungoverned, which is the
misread this paragraph would otherwise invite — records that the refusing merge_group leg
only reports until the ruleset toggle is flipped, and points coverage at the script's own
GOVERNED_SURFACES rather than restating a closed inventory that goes stale the next time a
guard is added. That last part is the paragraph's own promise being kept in a form that
cannot rot the same way.

The divergence clause (amended at 623b713)

The paragraph's closing clause originally described the guard-vs-carve-out divergence as an
open adjudication. That was stale on arrival: the maintainer had already ruled it on
2026-08-30 (第 5 场决裁批 #7, verbatim 「批 #7 同意」 — Option A, ui#6866 comment
5469339478). The clause now records the ruling itself — published skills/** is governed,
the guard's reading is the ruled one, implementation pending on #6866 — and forbids acting
on the carve-out until that lands. The carve-out sentences at AGENTS.md:419/:421 remain
byte-identical in this PR; their Option-A rewrite is #6866's follow-up implementation,
deliberately not folded in here.

Not in this PR

Validation

Round 1 at 64d6421, amend re-run at 623b713; exit codes captured before any pipe.

checkexitverdict line
check:control-bytes0✅ check-control-bytes: OK (scanned 5804 tracked text file(s); skipped 85 binary).
check:doc-fences0✅ check:doc-fences — every TypeScript block in 224 document(s) is fenced ts/tsx/typescript
check:governed-queue-guard0OK check-governed-queue-guard self-test: 132 cases pass
check-changeset-presence.mjs0✅ No source of a released package changed in this range, so no changeset is owed.
check-doc-links.mjs0Links are valid across 17 scan roots.
all 4 hook self-tests0121 passed, 0 failed · 41 passed, 0 failed · 36 passed, 0 failed

Anchored greps with positive controls (after the amend): --no-track1 in each file;
本仓没有任何机械兜底0; 本段没点名的兜底工具0; 这一分歧在 #6866 待维护者裁决0;
批 #71; controls — 受管面 in AGENTS.md7; PreToolUse5;
guard-shared-stash.sh in CLAUDE.md1. Line totals unchanged: CLAUDE.md 51,
AGENTS.md 489 — net 0 lines in both.

The guard, run against this PR's own file list, agrees with what the new paragraph says
about it:

⛔ GOVERNED — 2 of 3 path(s) are on a governed surface:
AGENTS.md x1 — the repo-root agent instruction file
CLAUDE.md x1 — the repo-root Claude instruction file
⛔ Do not flip it ready, enqueue it, or arm auto-merge. Park it as a DRAFT and leave the
merge to the maintainer; a human merge IS the review record for a governed surface.

Landing

Governed surface ⇒ draft, human merge (pm:awaiting-maintainer per 批 #7's execution
note). ⛔ Not flipped ready, not enqueued, no auto-merge. The changeset carries empty
frontmatter — this repo's measured form for a non-publishing change (precedent:
.changeset/6208-worktree-recipe-fetch-base.md, the same change class).

Generated by Claude Code

…o-backstop claim
Two instruction-file corrections on the same governed face.
**The prescribed worktree recipe now specifies `--no-track`** (`CLAUDE.md`, `AGENTS.md`).
Plain `-b` writes the new branch's upstream keys — `branch.NAME.remote` and
`branch.NAME.merge` — into the one `.git/config` that 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 in the very first step of the recipe, and one the error text does
not name. Read as "the whole command failed", the retry hits `branch already exists` and
reads as a second, unrelated problem; read as "the worktree exists", the agent starts
editing the shared primary checkout — the one thing the worktree-first rule exists to
prevent.
Measured on git 2.43.0: `--no-track` removes the config write and still bases the worktree
on `origin/main`. Explicit `git pull origin main` is unaffected (it uses the given refspec,
never `branch.NAME.merge`), and `git push -u origin BRANCH` — already the prescribed first
push — sets an upstream one command later.
**The governed-surface section no longer claims this repo has no mechanical backstop.**
The paragraph asserted that nothing mechanical covers the governed surface here, that the
sibling repo's post-merge audit does not cover this repo, and — self-referentially — that
"a backstop this paragraph does not name is a backstop that does not exist". Measured
today, three of those claims are false: `.github/workflows/governed-surface-guard.yml` is
live and reports on every pull request, and the sibling audit has covered this repo since
objectstack#9619. The same file already named the guard 59 lines above, so the document
contradicted itself.
The replacement keeps what is still true (no CODEOWNERS, no hook, not yet a required
check), names the guard and its two legs — the `pull_request` leg deliberately exits 0, so
green does not mean ungoverned — records that it stays report-only until the ruleset
toggle is flipped, and points coverage at the script's own list instead of restating a
closed inventory that goes stale the next time a guard is added.
Net 0 lines in both files; the changeset carries empty frontmatter because no published
package's source changed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
…ause
One clause in the corrected backstop paragraph said the guard-versus-carve-out
divergence on published `skills/**` was awaiting the maintainer. It is not: the
ruling landed 2026-08-30 (director session, ruling batch 7, maintainer verbatim
「批 #7 同意」) taking Option A — published `skills/**` is governed, human merge,
with the 2026-08-26 md-versus-code split written in alongside it. The earlier
routing that described it as undecided was made from the card body alone and has
been withdrawn on the card.
The clause now states that the divergence is ruled, cites the ruling comment,
and says the guard's reading is the decided one — while noting the carve-out
text above has not yet been rewritten, so a reader must not act on it in the
meantime. Rewriting that text is the separate implementation card's job, not
this PR's.
Word-level edit inside the existing line: the paragraph stays one line, both
files keep their line totals (AGENTS.md 489, CLAUDE.md 51), and the carve-out
sentences remain byte-identical to origin/main.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:17
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit ba55fb5Aug 31, 2026
30 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6880-worktree-recipe-hardening branch August 31, 2026 07:30
os-sam pushed a commit that referenced this pull request Aug 31, 2026
Conflict resolution, one file, one hunk: the backstop paragraph.
While this branch sat in the merge queue, the maintainer landed #6976
(ba55fb5), which rewrote the same paragraph under the title "correct the
stale no-mechanical-backstop claim". That paragraph is authoritative and is
taken VERBATIM; this branch's competing rewrite of it is discarded in full,
not blended. Byte-checked: the whole paragraph up to its trailing caveat
clause is identical to origin/main (sha256 of the 1393-byte prefix matches),
including the CODEOWNERS sentence, the "尚未是 required context" sentence and
"在翻转之前,那条拒绝腿只报告、不阻止队列".
The branch's remaining edits auto-merged and are re-derived rather than
replayed: the list heading 四项 -> 五项, the new repo-root `skills/**` row
(`GOVERNED_SURFACES`'s `skills-catalog`), the docs/adr row's 上面三项 ->
上面四项 (verified: exactly 4 rows precede it), the ⚠️ block flipped to
"both skills trees are governed" while keeping `.agents/skills/` NOT governed,
and the inverted-scolding paragraph, which still taught the retired
".claude/-prefix" criterion on main and now records it as the past error.
One consequential edit beyond the branch: the maintainer's own trailing
caveat said the script's set and the list above "并不一致 ... 落地仍挂在
#6866 上,在它落地前 ⛔ 不要照上面那条豁免行事". This commit IS that landing,
so the clause is updated minimally to record the ruling as landed and the old
exemption as void. Nothing else in the paragraph is touched.
The ruling being implemented is the maintainer's 5th adjudication batch item
#7, Option A, recorded on #6866 comment 5469339478. No ruling is made here.
Verification (offline; both scripts import only node: builtins plus
scripts/invoked-as.mjs, so no install is in their closure):
node scripts/check-governed-queue-guard.mjs --self-test -> exit 0,
"OK check-governed-queue-guard self-test: 132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.md -> exit 3,
"⛔ GOVERNED — 1 of 1 path(s) are on a governed surface"
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
huangyiirene pushed a commit that referenced this pull request Aug 31, 2026
…diation text
`.claude/hooks/guard-main-checkout.sh` and `.claude/hooks/guard-main-checkout-bash.sh`
each end their block message with the worktree recipe to run instead, and both created
the branch with a plain `-b`. PR #6976 hardened the prescribed form in `CLAUDE.md` and
`AGENTS.md`; the hooks' copy was left behind — and it is the higher-leverage copy,
delivered at the exact moment an agent is about to act, so it is the one most likely to
be run verbatim.
The hazard is the one #6976 established: plain `-b` writes the new branch's upstream keys
(`branch.NAME.remote`, `branch.NAME.merge`) into the one `.git/config` that 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. Read as "the
worktree exists", the agent starts editing the shared primary checkout, which is the one
thing these two guards exist to prevent.
Additive, not a recipe rewrite: this repo's hooks already emitted the fetch-hardened base
(`git fetch origin main && … origin/main`, landed for ui#6208), so the missing flag was
the only surviving divergence from the prescribed form. One word added per file, net ±0
lines in both.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationpm:awaiting-maintainer

Projects

None yet

3 participants

@zhuangjianguo@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim by zhuangjianguo · Pull Request #6976 · objectstack-ai/objectui · GitHub
Skip to content

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim - #6976

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening
Aug 31, 2026
Merged

docs: harden the worktree recipe with --no-track; correct the stale no-mechanical-backstop claim#6976
os-zhuang merged 2 commits into
mainfrom
claude/issue-6880-worktree-recipe-hardening

Conversation

@zhuangjianguo

@zhuangjianguozhuangjianguo commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6880
Part of #6866 — its half 1 stays open (implementation tracked there) and is untouched here.

Two instruction-file corrections on the same governed face, folded into one PR because they
land in the same file and would otherwise be hard-serial.

1. The worktree recipe now specifies --no-track (the anchor card)

Byte-level insert into the two prescribed spellings, net 0 lines:

  • CLAUDE.md:16 — the fenced recipe.
  • AGENTS.md:234 — the same recipe inline.

(Placeholders written as words here; the files use angle-bracket placeholders.)

Plain -b writes the new branch's upstream keys — branch.NAME.remote and
branch.NAME.merge — into the one .git/config that 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 in the very first step of the recipe, and one the error text does not
name. Read as "the whole command failed", the retry hits branch already exists and reads
as a second, unrelated problem; read as "the worktree exists", the agent starts editing the
shared primary checkout — the single thing the worktree-first rule exists to prevent.

The measured basis is the anchor card's git 2.43.0 table, cited rather than re-derived:
--no-track removes the config write and still bases the worktree on origin/main;
explicit git pull origin main is unaffected (it uses the given refspec, never
branch.NAME.merge), and git push -u origin BRANCH — already the prescribed first push —
sets an upstream one command later.

This PR ate its own dogfood: its worktree was created with the hardened recipe.

Scope pin honoured (anchor triage, comment 5473464940)

p2 · pm:queue · domain:skills — scope pinned to the FLAG INSERT ONLY. [...] ⛔ The
prose extension (naming .git/config beside refs/stash / refs/remotes/*) is NOT in
scope here: its objectstack companion #13052-A is HELD for corpus audit objectstack#13597,
and the shared-namespace prose should be shaped by that audit in both repos at once.

No shared-namespace prose was extended. .git/config appears nowhere new in the
instruction text.

2. The "no mechanical backstop" paragraph, corrected in place (#6866 half 2)

Scope pin honoured (comment 5473466315)

Half 2 [...] is a plain correction and stays dispatchable now, independent of half 1:
name the guard, its report-only-vs-blocking state (#6596 still pm:awaiting-maintainer),
and its coverage, per the paragraph's own 「它会写在这里」 promise. Governed file ⇒ draft,
human merge.

The paragraph re-derived to AGENTS.md:433 (the card's :392 had drifted). Claim by claim,
measured on this branch's base:

claim in the paragraphverdict
"this repo has NO mechanical backstop, this paragraph is all there is"FALSE — the guard workflow is live
no CODEOWNERS (verified: the file does not exist)still TRUE — absent at every candidate path
no required check on the governed surfacestill TRUE — the ruleset toggle is pending on #6596
no hook on the governed surfacestill TRUE
no post-merge audit lists governed merges for anyoneFALSE
the sibling repo's audit "does not cover this repo"FALSE — it has covered four governed repos since objectstack#9619
a violation "succeeds silently, nobody is notified"FALSE — the guard reports on every PR
"a backstop this paragraph does not name is a backstop that does not exist"self-referential closure — removed

Two of those were not in the card and turned up while reading: the audit-coverage sentence
is false for the same reason the headline claim is, and it sits in the same paragraph, so
leaving it would have meant knowingly shipping a corrected paragraph that still asserts a
measured-false absence.

⭐ The sharpest corroboration is internal: the same file already named the guard 59 lines
above
, at AGENTS.md:372-376, as the workflow a tree enumeration missed. The document
contradicted itself, and the half asserting the absence was the half written to be trusted
absolutely.

The replacement keeps every claim that is still true, then names the guard
(.github/workflows/governed-surface-guard.yml, check Governed Surface Queue Guard,
predicate in scripts/check-governed-queue-guard.mjs), states both legs — the
pull_request leg deliberately exits 0, so green does not mean ungoverned, which is the
misread this paragraph would otherwise invite — records that the refusing merge_group leg
only reports until the ruleset toggle is flipped, and points coverage at the script's own
GOVERNED_SURFACES rather than restating a closed inventory that goes stale the next time a
guard is added. That last part is the paragraph's own promise being kept in a form that
cannot rot the same way.

The divergence clause (amended at 623b713)

The paragraph's closing clause originally described the guard-vs-carve-out divergence as an
open adjudication. That was stale on arrival: the maintainer had already ruled it on
2026-08-30 (第 5 场决裁批 #7, verbatim 「批 #7 同意」 — Option A, ui#6866 comment
5469339478). The clause now records the ruling itself — published skills/** is governed,
the guard's reading is the ruled one, implementation pending on #6866 — and forbids acting
on the carve-out until that lands. The carve-out sentences at AGENTS.md:419/:421 remain
byte-identical in this PR; their Option-A rewrite is #6866's follow-up implementation,
deliberately not folded in here.

Not in this PR

Validation

Round 1 at 64d6421, amend re-run at 623b713; exit codes captured before any pipe.

checkexitverdict line
check:control-bytes0✅ check-control-bytes: OK (scanned 5804 tracked text file(s); skipped 85 binary).
check:doc-fences0✅ check:doc-fences — every TypeScript block in 224 document(s) is fenced ts/tsx/typescript
check:governed-queue-guard0OK check-governed-queue-guard self-test: 132 cases pass
check-changeset-presence.mjs0✅ No source of a released package changed in this range, so no changeset is owed.
check-doc-links.mjs0Links are valid across 17 scan roots.
all 4 hook self-tests0121 passed, 0 failed · 41 passed, 0 failed · 36 passed, 0 failed

Anchored greps with positive controls (after the amend): --no-track1 in each file;
本仓没有任何机械兜底0; 本段没点名的兜底工具0; 这一分歧在 #6866 待维护者裁决0;
批 #71; controls — 受管面 in AGENTS.md7; PreToolUse5;
guard-shared-stash.sh in CLAUDE.md1. Line totals unchanged: CLAUDE.md 51,
AGENTS.md 489 — net 0 lines in both.

The guard, run against this PR's own file list, agrees with what the new paragraph says
about it:

⛔ GOVERNED — 2 of 3 path(s) are on a governed surface:
AGENTS.md x1 — the repo-root agent instruction file
CLAUDE.md x1 — the repo-root Claude instruction file
⛔ Do not flip it ready, enqueue it, or arm auto-merge. Park it as a DRAFT and leave the
merge to the maintainer; a human merge IS the review record for a governed surface.

Landing

Governed surface ⇒ draft, human merge (pm:awaiting-maintainer per 批 #7's execution
note). ⛔ Not flipped ready, not enqueued, no auto-merge. The changeset carries empty
frontmatter — this repo's measured form for a non-publishing change (precedent:
.changeset/6208-worktree-recipe-fetch-base.md, the same change class).

Generated by Claude Code

…o-backstop claim
Two instruction-file corrections on the same governed face.
**The prescribed worktree recipe now specifies `--no-track`** (`CLAUDE.md`, `AGENTS.md`).
Plain `-b` writes the new branch's upstream keys — `branch.NAME.remote` and
`branch.NAME.merge` — into the one `.git/config` that 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 in the very first step of the recipe, and one the error text does
not name. Read as "the whole command failed", the retry hits `branch already exists` and
reads as a second, unrelated problem; read as "the worktree exists", the agent starts
editing the shared primary checkout — the one thing the worktree-first rule exists to
prevent.
Measured on git 2.43.0: `--no-track` removes the config write and still bases the worktree
on `origin/main`. Explicit `git pull origin main` is unaffected (it uses the given refspec,
never `branch.NAME.merge`), and `git push -u origin BRANCH` — already the prescribed first
push — sets an upstream one command later.
**The governed-surface section no longer claims this repo has no mechanical backstop.**
The paragraph asserted that nothing mechanical covers the governed surface here, that the
sibling repo's post-merge audit does not cover this repo, and — self-referentially — that
"a backstop this paragraph does not name is a backstop that does not exist". Measured
today, three of those claims are false: `.github/workflows/governed-surface-guard.yml` is
live and reports on every pull request, and the sibling audit has covered this repo since
objectstack#9619. The same file already named the guard 59 lines above, so the document
contradicted itself.
The replacement keeps what is still true (no CODEOWNERS, no hook, not yet a required
check), names the guard and its two legs — the `pull_request` leg deliberately exits 0, so
green does not mean ungoverned — records that it stays report-only until the ruleset
toggle is flipped, and points coverage at the script's own list instead of restating a
closed inventory that goes stale the next time a guard is added.
Net 0 lines in both files; the changeset carries empty frontmatter because no published
package's source changed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
…ause
One clause in the corrected backstop paragraph said the guard-versus-carve-out
divergence on published `skills/**` was awaiting the maintainer. It is not: the
ruling landed 2026-08-30 (director session, ruling batch 7, maintainer verbatim
「批 #7 同意」) taking Option A — published `skills/**` is governed, human merge,
with the 2026-08-26 md-versus-code split written in alongside it. The earlier
routing that described it as undecided was made from the card body alone and has
been withdrawn on the card.
The clause now states that the divergence is ruled, cites the ruling comment,
and says the guard's reading is the decided one — while noting the carve-out
text above has not yet been rewritten, so a reader must not act on it in the
meantime. Rewriting that text is the separate implementation card's job, not
this PR's.
Word-level edit inside the existing line: the paragraph stays one line, both
files keep their line totals (AGENTS.md 489, CLAUDE.md 51), and the carve-out
sentences remain byte-identical to origin/main.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EXxTW8mvPBhoHxmyPZ63de
@os-zhuang
os-zhuang marked this pull request as ready for review August 31, 2026 07:17
@os-zhuang
os-zhuang added this pull request to the merge queueAug 31, 2026
Merged via the queue into main with commit ba55fb5Aug 31, 2026
30 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-6880-worktree-recipe-hardening branch August 31, 2026 07:30
os-sam pushed a commit that referenced this pull request Aug 31, 2026
Conflict resolution, one file, one hunk: the backstop paragraph.
While this branch sat in the merge queue, the maintainer landed #6976
(ba55fb5), which rewrote the same paragraph under the title "correct the
stale no-mechanical-backstop claim". That paragraph is authoritative and is
taken VERBATIM; this branch's competing rewrite of it is discarded in full,
not blended. Byte-checked: the whole paragraph up to its trailing caveat
clause is identical to origin/main (sha256 of the 1393-byte prefix matches),
including the CODEOWNERS sentence, the "尚未是 required context" sentence and
"在翻转之前,那条拒绝腿只报告、不阻止队列".
The branch's remaining edits auto-merged and are re-derived rather than
replayed: the list heading 四项 -> 五项, the new repo-root `skills/**` row
(`GOVERNED_SURFACES`'s `skills-catalog`), the docs/adr row's 上面三项 ->
上面四项 (verified: exactly 4 rows precede it), the ⚠️ block flipped to
"both skills trees are governed" while keeping `.agents/skills/` NOT governed,
and the inverted-scolding paragraph, which still taught the retired
".claude/-prefix" criterion on main and now records it as the past error.
One consequential edit beyond the branch: the maintainer's own trailing
caveat said the script's set and the list above "并不一致 ... 落地仍挂在
#6866 上,在它落地前 ⛔ 不要照上面那条豁免行事". This commit IS that landing,
so the clause is updated minimally to record the ruling as landed and the old
exemption as void. Nothing else in the paragraph is touched.
The ruling being implemented is the maintainer's 5th adjudication batch item
#7, Option A, recorded on #6866 comment 5469339478. No ruling is made here.
Verification (offline; both scripts import only node: builtins plus
scripts/invoked-as.mjs, so no install is in their closure):
node scripts/check-governed-queue-guard.mjs --self-test -> exit 0,
"OK check-governed-queue-guard self-test: 132 cases pass"
node scripts/check-governed-queue-guard.mjs --test AGENTS.md -> exit 3,
"⛔ GOVERNED — 1 of 1 path(s) are on a governed surface"
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013hfmP9hoMd3dJwTh85J4yB
huangyiirene pushed a commit that referenced this pull request Aug 31, 2026
…diation text
`.claude/hooks/guard-main-checkout.sh` and `.claude/hooks/guard-main-checkout-bash.sh`
each end their block message with the worktree recipe to run instead, and both created
the branch with a plain `-b`. PR #6976 hardened the prescribed form in `CLAUDE.md` and
`AGENTS.md`; the hooks' copy was left behind — and it is the higher-leverage copy,
delivered at the exact moment an agent is about to act, so it is the one most likely to
be run verbatim.
The hazard is the one #6976 established: plain `-b` writes the new branch's upstream keys
(`branch.NAME.remote`, `branch.NAME.merge`) into the one `.git/config` that 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. Read as "the
worktree exists", the agent starts editing the shared primary checkout, which is the one
thing these two guards exist to prevent.
Additive, not a recipe rewrite: this repo's hooks already emitted the fetch-hardened base
(`git fetch origin main && … origin/main`, landed for ui#6208), so the missing flag was
the only surviving divergence from the prescribed form. One word added per file, net ±0
lines in both.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EnE7G31tqbxN1rqpQmzurT
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationpm:awaiting-maintainer

Projects

None yet

3 participants

@zhuangjianguo@os-zhuang@claude