Skip to content

chore(hooks): remove the client-side enqueue guard hook — the merge_group queue guard is the line - #18478

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-18470-remove-enqueue-guard-hook
Sep 16, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/issue-18470-remove-enqueue-guard-hook

Conversation

@hotlong

@hotlong hotlong commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Fixes #18470

Executes maintainer ruling B on PR #18447 — reply verbatim 「b」, then 「这个卡你也直接派发」: remove the client-side enqueue guard hook entirely. The server-side line stays: scripts/pm/check-governed-queue-guard.mjs on the merge_group build (reads reviews live and refuses an unapproved governed PR) plus the .claude/settings.json deny roster for the MCP enqueue class, plus the approver's click.

What changed

file change
.claude/hooks/guard-governed-enqueue.sh deleted (624 lines)
.claude/hooks/guard-governed-enqueue.selftest.sh deleted (633 lines)
.claude/settings.json the standalone MCP-enqueue matcher entry (enable_pr_auto_merge / merge_pull_request) removed — this hook was its only command; the one guard-governed-enqueue.sh command block removed from the Bash matcher. 13 lines, all removals. permissions (incl. the 17-entry deny) is byte-identical to origin/main; the Edit matcher and the other four Bash hooks are unchanged and in their original order.
scripts/pm/check-governed-merges.mjs two comments re-keyed: the --test stderr note no longer names the hook as the stdout consumer (stdout stays a machine-read --json surface for any caller). No code change.
scripts/pm/check-governed-queue-guard.mjs the authorizedApprovalVerdict docblock re-keyed: the importer note now records that the seat-side hook was removed by ruling and that the queue leg is this function's only consumer; the rename fence stays as "grep for importers in the same diff". Refusal logic untouched — 238 self-test cases pass unchanged.
scripts/pm/check-settings-deny-roster.mjs two header paragraphs re-keyed: the deny roster is now the only seat-side refusal of the MCP enqueue class; the hook is no longer described as defence in depth. CONTENT_WRITE_TOOLS untouched — 36 self-test cases pass, 17 declared = 17 enforced.

Not touched, by ruling: the deny roster, CODEOWNERS, check-governed-queue-guard.mjs's refusal logic; and #18468's surface (.claude/skills/pm-dispatch/SKILL.md:92, scripts/pm/check-harness-current.mjs).

Premise check against origin/main (BASE 8fe5cb8e)

git grep -l guard-governed-enqueue origin/main → exactly six files: the two hook files, .claude/settings.json, check-governed-merges.mjs, check-governed-queue-guard.mjs, check-settings-deny-roster.mjs. Neither scripts/pm/dispatch-gates.mjs nor package.json names the hook or its self-test: no family runs it, and lint.yml's hook self-test step discovers *.selftest.sh with find at run time, so the deletion needs no edit there (it now discovers 5).

Prose grep (deliverable step 4), all zero lines describing the hook as a live control: grep -rn -iE 'enqueue[ -]guard|governed[ -]enqueue|guard.governed.enqueue|GOVERNED_ENQUEUE|enqueue hook|seat-side hook|PreToolUse|client-side|客户端|钩子' .claude/skills .claude/agents AGENTS.md CLAUDE.md docs/adr. The PreToolUse mentions in AGENTS.md (lines 221, 323) and .claude/agents/os-dev.md (line 27) are the worktree and stash guards; platform-readings.md:395 names the CI context Governed Surface Queue Guard (server-side, stays); scripts/pm/check-half-states.mjs says "governed enqueue" three times about the queue guard's refusal, not the hook. So no SKILL.md, AGENTS.md or ADR line changes in this PR.

Gates green by design — no exemption for a missing file, no weakened assertion

Acceptance: git ls-files .claude/hooks/guard-governed-enqueue* → 0; grep -rn guard-governed-enqueue .claude scripts AGENTS.md CLAUDE.md docs .github package.json → 0 hits.

node scripts/pm/dispatch-gates.mjs --commands (no paths — derived from the merge base) → 40 commands at 9784cd23; identical list on the merged head afd9fcb2. Every command run with its exit code captured before any pipe (cmd > log 2>&1; ec=$?):

  • 39 exit 0 on the first pass. pnpm --filter @objectstack/lint run check:doc-formula-expressions exited 3 = PREREQUISITE NOT MET (@objectstack/formula and @objectstack/lint unbuilt — nothing measured, not a finding); after turbo run build --filter=@objectstack/formula --filter=@objectstack/lint under os-verify-lock.sh (VERDICT command-exit 0, turbo cache hit) it re-ran at exit 0.
  • dispatch-gates.mjs --ran on afd9fcb2: 40 derived, 40 run, 0 NOT-MEASURED, 0 UNRUN — "a DERIVED zero — all 40 recorded an exit code and none of them is 3".
  • Named gates: check:pm-settings-deny-roster — 36 self-test cases, 17 content-write tools declared = enforced; check:pm-governed-merges — 328 assertions; check-governed-queue-guard.mjs --self-test — 238 cases; check:pm-dispatch-gates, check:nul-bytes, check-harness-current.mjs --self-test, check:cross-package-test-inputs — exit 0; check:bash32-floor — exit 0, re-run on the merged head after main moved that script (31 tracked shell files, none naming a bash 4+ construct).
  • Hook self-tests (what lint.yml discovers): 5 discovered, all pass — guard-main-checkout-bash 130, guard-main-checkout 120, guard-process-kill 69, guard-shared-stash 53, guard-tree-enum 38.
  • After merging origin/main (85c6d76e: two docs commits — check-bash32-floor.mjs +41, two SKILL.md lines): check:skill-frame-sync, check-skills-token-ratchet.mjs (and its --self-test), check:pm-dispatch-gates re-run at exit 0 on afd9fcb2.
  • Not run: check:pm-skill-ratchet / check:pm-skill-id-lint — no .claude/skills/** line changes in this diff (the SKILL.md ratchet stays 812/812).

Lint, proven narrowing at afd9fcb2: ① population read from eslint.config.mjs — the base block lints **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} minus NEVER_LINTED; .claude/settings.json reports "File ignored because no matching configuration was supplied", and the two deleted .sh files match no glob, so this diff's lint population is exactly the three .mjs files; ② --format json count: 3 files, 0 errors, 0 warnings; ③ invariance: the config "never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file" (its own line 327), so no untouched file's verdict can move with this diff. The repo-wide pnpm lint is CI's run.

Changeset

skip-changeset — route 2 in check-empty-changeset.mjs: a PR touching only .claude/ and scripts/ releases nothing, and no package files[] ships either surface. Label applied by REST POST /issues/NUMBER/labels and read back.

Acceptance notes

  • noted, not filed: scripts/pm/check-half-states.mjs (lines 9377, 9557, 29094) says "governed enqueue" about the queue guard's refusal — still true after this PR, no edit. 承接者:无.
  • Control-character scan on the four edited files: clean. Commit 9784cd23 carries the model-free trailer pair; afd9fcb2 is the merge of origin/main.
  • Governed surface (.claude/**): this PR stays DRAFT; the dev seat flips nothing, requests nothing and arms nothing. needs:contract-review is the seat's.

维护者速读(草稿)

改了什么
删掉客户端入队守卫钩子 guard-governed-enqueue.sh 及其自检脚本,.claude/settings.json 里的两处注册一并去掉;三个 PM 门禁脚本里把它描述为"在场控制"的注释改写成现状。deny 名单、CODEOWNERS、check-governed-queue-guard.mjs 的拒绝逻辑一字未动。

为什么改
执行 PR #18447 上的裁决 B(维护者原话「b」,随后「这个卡你也直接派发」)。真正的硬线是 check-governed-queue-guard.mjsmerge_group 构建上的拒绝,加上维护者的批准点击;这个钩子只省一个队列周期,而实装版本盯着三种合规席位根本不用的拼法,今天已经耗掉三个受管 PR。删除优于继续维护。

风险与代价(含回滚)
风险:失去"批准前就在本地拦住"的便宜防线——违规入队会在队列里红一次,而不是在本地被拦;服务端正确性不变。代价:一次受管落地即一次 harness 重载(#18468 已把"重开"处方去掉)。回滚 = revert 本 PR 的 squash 提交,钩子与两处注册整体回来。

席位意见
(留空,席位定稿)

你要做的
一个动作:在本 PR 上 Approve;落地由拥有席位按受管流程执行。


Generated by Claude Code

Delete .claude/hooks/guard-governed-enqueue.sh and its self-test, drop
both settings.json registrations that named it, and re-key the three PM
gate headers that described it as a live control. The deny roster and
every other hook registration are byte-identical; the merge_group queue
guard (check-governed-queue-guard.mjs) remains the line.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wj1HUjzyeiBQ8atRf1ZhaL

hotlong commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

维护者速读(终稿)

总监席,session_01Wj1HUjzyeiBQ8atRf1ZhaL。席内复核 ACCEPT 记录在卡 #18470。受管面(.claude/**)⇒ 等一位授权批准账号 APPROVED 后由席位落地;在此之前保持 draft。

改了什么 删掉客户端入队守卫钩子 guard-governed-enqueue.sh 及其自测(−1,288 行),settings.json 去掉它的两处注册(一个只为它存在的 MCP 入队 matcher、Bash matcher 里的一条命令);permissions 含 17 条 deny 表一字未动;三个 PM 脚本只改注释,说明这个钩子已按裁决拆除、队列守卫 + deny 表是唯一的线。

为什么改 你的裁决 B(「b」):真正拦住未批准受管 PR 入队的是 merge_group 里的 CI 守卫(09-01 实证守住)+ 你的批准点击;这个钩子只省一个队列周期,而且它盯的三种拼法合规席位一种都不用、今天被返工三遍。

风险与代价(含回滚) 风险:席位违规把未批准的受管 PR 挂 auto-merge 时,多烧一个队列周期 + 一条红条目,合并仍被拦。代价零。回滚 = revert 一个 squash 提交。

席位意见 建议批准。deny 表逐字节核过相同,五个保留钩子顺序不变,五份钩子自测全绿。

你要做的 一个动作:在本 PR 上 Approve。与 #18476 互不依赖,先批哪个先落哪个。


Generated by Claude Code

@hotlong
hotlong requested a review from os-zhuang September 16, 2026 15:03
@hotlong hotlong self-assigned this Sep 16, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 16, 2026 15:31
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 16, 2026

hotlong commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

Landing provenance (ruling C) — director seat, session_01Wj1HUjzyeiBQ8atRf1ZhaL · 2026-09-16T15:33Z

Governed surface (.claude/**). Readings at landing, head afd9fcb2: APPROVED by os-zhuang (review 5224805455, 2026-09-16T15:31:54Z) on this exact head; check-clause2-carriers --pair 18478 exit 0 (Clause-②: no, no widening tell); CI 24 success · 15 skipped, Governed Surface Queue Guard re-running after the approval; in-seat ACCEPT on #18470 (stamped 2026-09-16T15:03Z). The approver flipped ready and the PR entered the merge queue at 2026-09-16T15:31:59Z (added_to_merge_queue on the timeline); the seat stripped needs-user-decision and confirmed auto-merge (PUT …/ccr/auto_mergeenabled: true, squash). Nothing else remains for a person. Followed to MERGED by the director's check-in.


Generated by Claude Code

Merged via the queue into main with commit 674872a Sep 16, 2026
44 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-18470-remove-enqueue-guard-hook branch September 16, 2026 15:58
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 17, 2026
… list, report-only (ruling F) (objectstack-ai#18497)

Fixes objectstack-ai#18472

`skip-changeset`: the diff is one file under `docs/audits/`, which no
released package's `files[]` ships.

## What this is

The gate census the maintainer's ruling **F** asked for, verbatim 「F」 on
「现在有各种门禁的开发在浪费我的各种时间,我们的项目是不是门禁用的太重了。有这个必要吗?」 — **one table,
report-only**. No gate is removed, disabled or edited by this PR; the
retirement batch is its own card(s) after the maintainer's one-word 「认可」
on the table.

`docs/audits/gate-census-2026-09.md`:

- **Inventories**: ① 182 check files (`scripts/**/check-*.mjs` 178 +
`packages/*/scripts/check-*.mjs` 4) · ② 26 root `check:*` scripts that
are not a thin alias (of 164; 138 collapse onto their file row) · ③ 10
hooks (5 PreToolUse guards + 5 self-tests; the base tree had 12 — objectstack-ai#18478
removed the enqueue guard on `main` after the base) · ④ 7 required
contexts (read from `GET
/repos/objectstack-ai/objectstack/rules/branches/main`) → **union = 225
rows**, the table has 225 rows.
- **Verdicts**: **retire 59** (58 rule-derived + `retire (ruled)` for
`check-reference-carrier-shape.mjs`, objectstack#18095 E) ·
**report-only 16** · **keep 150** (133 plain, 2 ruled — the governed
queue guard and its context —, 5 too new to judge, 5 session hooks + 5
hook self-tests).
- **Classes**: process 115 · contract 60 · correctness 50.
- **Column 5 (real catches)**: sampled over the last 30 days of failed
PR CI (2026-08-17..09-16): 1,230 failed runs in the eight PR-triggered
gate workflows, 1,287 failed jobs read step-by-step, 1,287 annotation
reads, 9 sampled job logs, attribution by step name, split by annotation
tag where a step hosts several gates, counted as distinct PRs, PRs that
edited the gate's own file excluded. Every zero is a measured zero;
every `unmeasured` names why; no count is guessed.
- **Three sections**: retirement list (per row: files to delete, root
scripts to drop, workflow `file:line`, count of other references to fix;
a nine-row CI-integrity sub-group presented as one decision),
report-only list, method + limits (incl. what is outside the four
inventories: 70 per-package `check:*`, 31 workflow-direct non-`check-*`
steps, two inline workflow gates — the inline `Require a changeset` step
alone reddened 107 PRs).
- Zod validation inside `packages/spec` / the runtime is the product,
out of scope, said in one line.

Standing verdicts recorded as given: `check-governed-queue-guard.mjs` =
`keep (ruled)`; `check-reference-carrier-shape.mjs` = `retire (ruled)`.

## Acceptance notes

- Dispatch-derived gates (`node scripts/pm/dispatch-gates.mjs --commands
docs/audits/gate-census-2026-09.md`, 17 families) all exit 0 on the
merged tree except `pnpm check:cross-package-test-inputs` (exit 1, at
the base and again on the merged tree): its finding names
`packages/cli/test/init-created-files-summary.e2e.test.ts` walking
`packages/spec/dist/` with no declared glob — not a path this diff
touches (one docs file). Reported to the seat in the dev report for
filing; not fixed here (scope rule).
- `pnpm --filter @objectstack/lint run check:doc-formula-expressions`
first answered exit 3 (PREREQUISITE NOT MET: `@objectstack/formula` and
`@objectstack/lint` not built) — built both through the verify lock and
re-ran: exit 0.
- noted, not filed: the four inventories the card defines leave 31
workflow-direct gate steps and two inline workflow gates without a row;
the census names them in Method so the union stays honest. 承接者: the
director's retirement batch (it decides whether a ⑤ is worth a follow-up
census).
- noted, not filed: two of the 25 `Docs anchors resolve to real
headings` step failures could not be attributed between
`check-doc-anchors.mjs` and `check-system-context-census.mjs` (no tag in
the annotation); recorded as `unmeasured` on the doc-anchors row. 承接者:
none.
- Drift: `origin/main` moved seven commits before this PR opened; the
branch merged `bf61f0a1` and the census was re-derived on the merged
tree (Drift paragraph in the file). objectstack-ai#18481 (the protocol flip: a
census-marked retirement becomes class-1) landed in that range and is
the other half of ruling F.
- Local verification scope: no package is touched, so no build/test
closure is owed; `packages/spec`, `@objectstack/formula` and
`@objectstack/lint` were built only as prerequisites of the derived
gates. Repo-wide scans (`pnpm lint`) are CI's.

## 维护者速读(草稿)

**改了什么**:新增一份审计文档
`docs/audits/gate-census-2026-09.md`,把仓库里全部门禁放到一张表上:182 个
`check-*.mjs`、26 个非别名的根 `check:*` 脚本、10 个 `.claude/hooks` 文件、7 个 main
分支必过的 CI 上下文,合计 225 行。每行六列:名字、类别(contract / correctness /
process)、守的是什么契约、是否必过与波及面、落地以来真实抓到过几次(近 30 天 1,230 次失败的 PR
运行逐步归因,去掉门禁自己的 PR)、结论。⛔ 本 PR 不删、不停、不改任何门禁。

**为什么改**:您在直连通道的裁决 **F**(「门禁是不是用的太重了」→ 先普查、再按表退役)。这张表就是普查结果:**59
行建议退役**(其中 1 行 `check-reference-carrier-shape` 是 objectstack-ai#18095 已裁 E),**16
行只是报告不拦合并**,**150
行保留**(含您已裁定保留的治理队列守卫)。波及面最大的三处:`check-changeset-no-major`(Clause-②
等级规则,30 天红了 **74 个 PR**)、`check-partof-closing-keyword`(**31 个
PR**,但它只在非必过的工作流里跑)、`check-system-context-census`(必过、全仓,**21 个
PR**)。表外还有一个最大的红源:`pr-automation.yml` 里的内联「Require a changeset」步骤,30 天红了
107 个 PR。

**风险与代价(含回滚)**:本 PR 只加一份文档,零运行时改动,回滚即删除该文件。真正的代价在下一步:退役清单里有 9 行是「CI
自身接线」的守卫(必过上下文名字钉、聚合器 needs 花名册、Node/pnpm 获取、self-test 接线等),按规则它们 30
天零抓获所以列为退役,但它们的价值是威慑而非抓获——表里把这 9 行单独成组,供您一次决定。抽样只有 30 天:一季度才响一次的门禁会读成零。

**席位意见**:(留空,席位定稿)

**你要做的**:读表,认可则回一个字「认可」;若对某行有异议(尤其 CI 接线 9 行组、以及 5 个会话 hook
的保留),点名该行即可,director 会把退役批次按您的意见立卡。

---
_Generated by [Claude
Code](https://claude.ai/code/session_01Wj1HUjzyeiBQ8atRf1ZhaL)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xl skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants