Skip to content

fix(agents,gates): the merge queue blocks on seven contexts, and a set-stating surface is now a census - #18244

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-17798-required-set-seven-exclusivity
Sep 15, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/issue-17798-required-set-seven-exclusivity

Conversation

@claude

@claude claude Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Fixes #17798

AGENTS.md's merge-queue paragraph named SIX required contexts and called everything else "advisory and rides through". The live ruleset has SEVEN — Governed Surface Queue Guard, enrolled 2026-08-27 (#12427) and pinned in REQUIRED_CONTEXTS by #15233. The sentence a review seat acts on therefore classified the one gate that refuses a zero-review governed PR as advisory, which is verbatim the incident shape that guard exists to prevent.

Nothing reddened on it, and that is the half worth fixing. mustName is a FLOOR: it reds when a listed literal goes stale and is blind to one going MISSING. So the registry grew, every surface's list stayed legal, every gate stayed green, and the sentence stayed behind. The same misclassification has now landed twice — 2 to 6 by the #9677 ruling, 6 to 7 here.

维护者速读(草稿)

改了什么。 两处。一、AGENTS.md 的合并队列段落从「六个必需上下文」改成七个,把第七个 Governed Surface Queue Guard 写进名单(等行数改写,1075 行没动)。二、scripts/check-required-contexts.mjsINSTRUCTION_SURFACES 增加一个 statesTheSet 声明:声明了它的文件,其名单必须与注册表逐个且等长地对上。注册表本身(REQUIRED_CONTEXTS)一行未动,那是 #15233 的面。

为什么改。 这句话不是描述,是审核席翻 ready / 挂 auto-merge / 入队前照着做的操作指令。它把治理面守卫说成 advisory,而那个守卫的职责恰恰是拒掉零审查的治理 PR —— #12427 的事故形态。更关键的是:上一次入列(#15233 加第七行)时,全部门禁是绿的,没有任何东西提示这句话已经过期。同一个漏洞已经发生两次,所以这次不只是手跟一遍数字,而是把「谁陈述了整个集合」变成机器可查的:下一次(第八个)入列时,加注册行的那个 PR 自己会变红。

风险与代价(含回滚)。 风险低。新规则只对显式声明 statesTheSet: true 的条目生效,今天是两个文件(AGENTS.md 与 pm-dispatch 的 platform-readings.md);review-checklist.md 被明确归类为不陈述集合(它点名的是审核席亲手确认的两个 job,不是集合),保留它原有的两名下限,集合变大不会误伤它。声明也不能被悄悄摘掉换取豁免:名单已覆盖整个集合却没声明的条目同样变红。代价:每次入列多一处必须同 PR 跟进的数组。回滚 = git revert,两个文件都是纯文本,没有生成物、没有发布面、没有数据迁移。

席位意见。

你要做的。 确认一件事:第七个上下文 Governed Surface Queue Guard 今天确实在 Settings 的必需集合里(卡面 2026-09-12 的实测读数是七个,本 PR 不改 Settings)。其余不需要你操作。本 PR 触及受管面 AGENTS.md,按 Prime Directive #14 走人工合并或已批准的队列路径。

What changed

1. AGENTS.md :505-:510 — six to seven. The seventh name inserted, "six" to "seven" in all three places, equal-line at the 1075 ceiling (before 1075 / after 1075 / ceiling 1075). Each context literal is kept whole on one line: the scan matches them contiguously, and a wrap that split TypeScript Type Check across a line break made the surface red. That is a real trap for the next hand-follow, so it is recorded here rather than only avoided.

2. INSTRUCTION_SURFACES gains statesTheSet. An entry that declares it must name the registry EXACTLY — membership and count:

review-checklist.md is classified the other way and keeps its two-name floor: it names the two required jobs a seat confirms by hand — its own next line sends the seat to true-green.md for the rest — so it never claimed to enumerate the set, and the set growing must not red it.

3. Ten self-test cases, battery floor 31 to 41. The 6-of-7 omission and its restore-leg ablation; the eighth-row enrolment end to end, plus the hand-off where following the ARRAYS clears the census red and leaves the naming floor demanding the PROSE; the padded duplicate; the undeclared full list; the no-declaration floor; and the two classification pins (which surfaces state the set, by NAME never by count; and the checklist's partial list staying legal).

Evidence

Baseline first, on origin/main b3b43b6 in a clean worktree, BEFORE any edit — the known pit from hold note 5651882793 (PR #17803 reported --self-test red on a pre-existing branches: [main] filter on governed-surface-guard.yml):

node scripts/check-required-contexts.mjs --self-test   exit 0   159 assertions
node scripts/check-required-contexts.mjs               exit 0   7 required context name(s) pinned across 3 workflow(s)

The known pit is NOT red on main today. The residual named in the hold note is gone; the work below is measured against a green baseline, not against a standing red.

After (78959ab): --self-test exit 0, 169 assertions; the pin exit 0.

Reverse verification, both legs from the committed implementation, each with its on-disk mutation proved and each restored byte-identical (git hash-object vs the HEAD blob, git diff HEAD empty):

leg mutation (proved on disk) result
A — the registry array rots back drop 'Governed Surface Queue Guard' from the AGENTS.md entry's mustName (grep 2 to 1; git diff --numstat 0/1) RED, exit 1: "declares statesTheSet: true, so its mustName must be the required set EXACTLY — it lists 6 name(s) against a registry of 7, missing 'Governed Surface Queue Guard'". Self-test exit 1 too.
B — the numeral alone rots back seven contexts block to six contexts block in AGENTS.md, all seven literals still listed (numstat 1/1) GREEN, exit 0 — reported as measured, not as expected. The scan pins literals, never the word introducing them. Recorded as a residual in the script header rather than implied covered.
B2 — the prose drops the literal delete and `Governed Surface Queue Guard` from the paragraph (grep 1 to 0; numstat 1/1) RED, exit 1: "AGENTS.md no longer names the required context 'Governed Surface Queue Guard'"
floor control battery floor 41 to 42 RED, exit 1, naming the exact count: "registered 41 case(s), below its pinned floor of 42" — so the floor binds at headroom 0 and 41 is the measured count, not a number below it

Leg B is the honest finding of this PR: the census forces every enrolled literal INTO the prose, so a stale numeral now sits next to a complete list rather than a short one. Bounded, not covered; pinning the numeral needs the arbitrary-literal recognition the script header already measured as out of reach.

Derived gate union, run after the final commit, on 78959ab (git rev-parse --short HEAD), each exit captured by redirect before any pipe:

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack
  -> 37 command(s) from a 2-path change set (AGENTS.md, scripts/check-required-contexts.mjs)

36 of 37 exit 0. The one not measured: pnpm check:pm-dispatch-gates (scripts/pm/check-dispatch-gates.mjs) runs past this session's foreground ceiling — it was still printing passing cases at 560s. NOT MEASURED, reason: runtime exceeds the foreground cap; CI owns it. Its subject matter — the ROOT_FILE_WATCH_HINTS declaration this file carries — is separately green under pnpm check:watch-hint-literal (exit 0) and under this script's own the dispatch-gates declaration (#9979) battery (6 assertions).

--ran reconciliation is reported in the dev report; the beyond-derivation families this card owes because it edits a gate script — check:required-contexts and its --self-test — are the two green readings above. git grep finds no *.test.* naming check-required-contexts.mjs, so that script has no separate test suite to owe.

Lint, narrowed with the three readings that make a narrowing a measurement:

  1. covered population read from eslint's own config, not guessed: npx eslint --print-config scripts/check-required-contexts.mjs reports exactly 2 rules enabled for this path (no-restricted-imports, comment-swallow/no-code-inside-block-comment); eslint.config.mjs declares no markdown population at all, so AGENTS.md is outside the lint verdict in either direction;
  2. file count read from --format json: 1 file, 0 errors, 0 warnings;
  3. invariance for untouched files: this repo runs one eslint.config.mjs which never enables type-aware linting for any file (no parserOptions.project, no typed rules — eslint.config.mjs :326-:329, with its own positive-control measurement recorded there), so this diff cannot move any untouched file's verdict.

The repo-wide pnpm lint scan is CI's run.

skip-changeset, measured rather than asserted: both paths lie outside every package directory, and of the 70 published packages none has a files[] entry escaping its own directory (0 entries starting with ../ or /). Nothing published moves.

Acceptance notes

Out of scope, noted, not filed:

  • .claude/skills/pm-dispatch/references/platform-readings.md :385-:386 becomes FALSE when this lands. It reads 「⭐ 本表的 mustName 不要求排他 ⇒ 第七个加注册行不会让本表变红」 and 「⇒ ⛔ 门绿不是本行已对的读数:计数行只能手跟改」. After this PR that entry declares statesTheSet: true and the registry growing DOES red it, so a seat reading those two lines would keep hand-following a line the gate now holds. Not fixed here: the file is outside this card's declared REGION claim (AGENTS.md :505-:510 plus this script), and the script's own header records .claude/skills/pm-dispatch/** as a surface a dev seat may not edit — the reason the checklist half of The ESLint required context carries ~54 check:* gates, so every one of their failures mis-routes its own diagnosis — and the rename needs a Settings change no agent seat can make #9325 was its own card. Successor: the domain:skills seat, in its own lane. Dedupe words: platform-readings, mustName 不要求排他, 计数行只能手跟改, statesTheSet, required contexts 的名单.
  • The count WORD in a set-stating surface stays hand-followed (leg B above). Recorded as a residual in the script header, in the paragraph that already records the paraphrase-drift and shortening-rename residuals. No card: it is bounded by the census and closing it needs recognition the header measured as out of reach.
  • The triage grading comment 5651027386, which this card's acceptance is quoted from, answers HTTP 404 — it is not on [finding] AGENTS.md states the merge queue's required set as six contexts and calls the rest advisory — it is seven, and no gate reds on the stale sentence #17798 (the card carries exactly 3 comments) and the direct comment endpoint does not find it. Its content survives verbatim inside hold note 5651882793 and in this dispatch's own text, which is what acceptance items 1, 2 and 4 were read from here. Recorded as NOT MEASURED against the primary source, not as "no flags".

Nothing else was touched. REQUIRED_CONTEXTS is byte-identical to origin/main.


Generated by Claude Code

…rface that states the set is now a census

AGENTS.md's merge-queue paragraph named six required contexts and called
everything else advisory-and-rides-through. The live ruleset has seven --
`Governed Surface Queue Guard`, enrolled 2026-08-27 -- so the sentence a review
seat acts on classified the one gate that refuses a zero-review governed PR as
advisory. That is verbatim the incident shape the guard exists to prevent.

Nothing reddened on it, and that is the half worth fixing. `mustName` is a
FLOOR: it reds when a listed literal goes stale and is blind to one going
MISSING, so growing the registry left every surface's list legal and every gate
green. The same misclassification has now landed twice (2->6, then 6->7).

- AGENTS.md :505-:510: six -> seven, the seventh name inserted, equal-line at
  the 1075 ceiling; each literal kept whole on one line, since the scan matches
  them contiguously.
- INSTRUCTION_SURFACES gains `statesTheSet`. An entry that declares it must name
  the registry EXACTLY -- count and membership -- so the next enrolment reds on
  the PR that adds the row. `review-checklist.md` is classified the other way
  and keeps its two-name floor: it names the two jobs a seat confirms by hand,
  not the set.
- The declaration cannot be dropped to buy the exemption (a full list with no
  `statesTheSet` reds), and ablating every declaration reds rather than ticking.
- Ten self-test cases, battery floor 31 -> 41: the 6-of-7 omission, its
  restore-leg ablation, the eighth-row enrolment end to end and its hand-off
  from the census red to the naming floor, the padded-duplicate count, the
  undeclared full list, and the no-declaration floor.

The `REQUIRED_CONTEXTS` registry itself is untouched.

Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr
Co-authored-by: Claude <[email protected]>
Ablating AGENTS.md's numeral back to "six" while all seven literals stay listed
runs GREEN: this scan pins literals, never the word that introduces them. The
census bounds it rather than covering it -- every enrolled literal is forced
into the prose, so a stale numeral sits next to a complete list -- and pinning
the numeral needs the arbitrary-literal recognition the header already measured
as out of reach.

Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr
Co-authored-by: Claude <[email protected]>
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 15, 2026
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation labels Sep 15, 2026
@claude

claude Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 78959abf83e8e5c8ff41607a6b69ab9876cd0356

Reviewing seat: domain:skills, in-seat review at the contract-review tier (get_session at 2026-09-15T02:54Z: configured = session = last served, the constant's tier). Card #17798, claim 5673630071, report 5674064155; Clause-②: no on the claim and in the PR body.

① Derived judgments

  • Accept set / public surface: none moves — AGENTS.md (+6/−6, the merge-queue paragraph :505–:510 only: six → seven, the seventh name Governed Surface Queue Guard inserted, all three count words moved; 1075/1075) and scripts/check-required-contexts.mjs (+195/−19: a declared statesTheSet flag on INSTRUCTION_SURFACES; an entry that declares it must name REQUIRED_CONTEXTS exactly — membership and count; a full list without the declaration reds; zero declarations red; review-checklist.md classified as not stating the set and kept at its two-name floor; ten self-test cases, floor 31 → 41). The REQUIRED_CONTEXTS registry is byte-identical to origin/main (acceptance 4). Nothing published; skip-changeset on the PR (read back with size/m, documentation).
  • Seat-read on the head in a detached worktree: the AGENTS.md hunk is exactly the region claimed; check-skill-line-ratchet ✓ (1075/1075, widest row 768 untouched); check-governed-prose ✓; the diff's exclusivity branch, the anti-exemption branch and the zero-declaration branch read as the report says. Seat-run on the PR head in a detached worktree at 78959ab (the review worktree's node_modules linked from a sibling install for the gate's yaml import): node scripts/check-required-contexts.mjs --self-test exit 0 — 169 assertions — and the scan exit 0 ( governed-surface-guard.yml:governed-surface-guard → 'Governed Surface Queue Guard').
  • The B2 baseline the dispatch named was FALSIFIED by the dev before editing (self-test and pin exit 0 on b3b43b6, 159 assertions, 7 contexts across 3 workflows): the known red on branches: [main] is not on main today, so every reading is against a green base.
  • Ablations reported from the committed fix with on-disk proof and blob-hash restores: dropping the seventh mustName literal ⇒ red naming it; deleting the literal from the paragraph ⇒ red; the floor control binds at headroom 0; rotting only the NUMERAL ⇒ green, reported as measured and recorded in the script header as a bounded residual (the census forces every literal into the prose, so a stale numeral sits beside a complete list) — accepted as the mechanism's stated boundary, not a defect.
  • Gates 37 / 37 / 0 / 0 per the report with exits captured by redirect; the check:pm-dispatch-gates family finished detached and its exit was read from its own verdict line (class (a): pnpm check:pm-dispatch-gates cannot complete inside the container's ~10-minute foreground cap — measured 9m0s then exit 124, twice; the wall-clock twin of #17708 #18201's cap, not this PR's); lint narrowed with the three pieces of evidence.

② Semver level

Not applicable — nothing published moves; skip-changeset measured (no package files[] escapes its directory).

③ Boundary flags

open_questions: none. Deviations (4), each answered: (1) triage comment 5651027386 answers 404 (the suspended triage account's content) — the acceptance survives verbatim inside hold note 5651882793, read as NOT MEASURED against the primary and accepted; (2) the PR body under-claims check:pm-dispatch-gates as NOT MEASURED while the detached run finished green — conservative direction, left as is (a body PATCH is outside the dev's budget; the record here is the correction); (3) the self-test floor raised 31 → 41, proved binding — accepted; (4) the ablation-trap process lesson (a trap on EXIT wiped an uncommitted fix; recovered and re-run from a committed tree) — recorded, no rule change. Out-of-scope class (b) finding (platform-readings :385–:386 become false when this PR lands) — filed by the seat as its own card in this lane, blocked on this card. Governed (AGENTS.md = rules layer) ⇒ four-piece: needs-user-decision on the PR, 速读终稿 below, reviews requested; ⛔ not flipped ready by the seat before an authorized approval. Serial: PR #18227 (devx, AGENTS.md :1026+) is disjoint; the second to land merges origin/main first.

Implemented-by: claude/issue-17798-required-set-seven-exclusivity
Reviewed-by: session_01HZfg2AwVX191qCizp88gQr

VERDICT: PASS


Generated by Claude Code

@claude

claude Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

维护者速读(终稿)

改了什么:两处。一、AGENTS.md 合并队列段落(:505–:510)从「六个必需上下文」改为七个,把第七个 Governed Surface Queue Guard 写进名单——等行数改写,1075 行不动。二、scripts/check-required-contexts.mjsINSTRUCTION_SURFACES 增加 statesTheSet 声明:声明了它的文件,其名单必须与注册表逐个且等长地对上;没声明却已列全的条目同样变红(不能靠摘声明换豁免);一个声明都没有也变红。注册表本身(REQUIRED_CONTEXTS)一行未动。

为什么改:那句话是审核席翻 ready / 挂 auto-merge / 入队前照着做的操作指令,它把治理面守卫说成 advisory,而那个守卫的职责恰恰是拒掉零审查的治理 PR。上一次入列(#15233 加第七行)时门禁全绿、没有任何东西提示句子已过期——同一漏洞发生了两次。这次不只手跟数字,而是让「谁陈述了整个集合」可查:下一次(第八个)入列时,加注册行的那个 PR 自己会红。

风险与代价(含回滚):风险低。新规则只对显式声明 statesTheSet: true 的条目生效(今天两个:AGENTS.md 与 pm-dispatch 的 platform-readings.md);review-checklist.md 归为「不陈述集合」,保留两名下限,集合变大不误伤。代价:每次入列多一处必须同 PR 跟进的数组。回滚 = git revert,纯文本,无生成物、无发布面、无迁移。一处已知残留:只改错「数字词」而名单齐全时门禁仍绿——已在脚本头记为机制边界。

席位意见:建议批准。本席核过:AGENTS.md hunk 恰为认领区域;棘轮 1075/1075、governed-prose 绿;排他/反豁免/零声明三个分支读法与报告一致;dev 在改动前先证伪了「主干自测本就红」的假设(基线绿),四组消融方向与报告一致。本席自跑该门禁的读数见 PR 上的复核记录;CI Lint & Repo Gates 仍在跑,绿后才由本席按裁决 C 落地。落地后事实表 :385–:386 两行会变假,已另立卡在本车道跟进。

你要做的(一个动作):approve 本 PR。approve 后本席翻 ready + 入队,你不必再点合并。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 15, 2026 06:06
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 15, 2026
@claude

claude Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

Ruling-C landing provenance — skills seat, session session_01HZfg2AwVX191qCizp88gQr, 2026-09-15T06:08Z. Authorized approval: os-zhuang's APPROVED review at 2026-09-15T06:06Z on head 78959abf83e8e5c8ff41607a6b69ab9876cd0356, the same head the review of record 5674090825 (## Contract review PASS) names and the ACCEPT 5674091300 on #17798 cites; not dismissed. The approver also flipped the PR ready (2026-09-15T06:06Z) and enqueued it (added_to_merge_queue 2026-09-15T06:06Z, actor os-zhuang; queue ref gh-readonly-queue/main/pr-18244-* present on origin at 2026-09-15T06:07Z), so the seat's remaining acts under ruling C are the readings and the label: check-clause2-carriers --pair 18244 exit 0 re-read at 2026-09-15T06:07Z with the C6-RECORD note naming that record; on that head Lint & Repo Gates and TypeScript Type Check both success and every other check is success or skipped; no main commit touches AGENTS.md :505–:510 or scripts/check-required-contexts.mjs since the merge-base, so no branch update was made (the queue builds the merge; PR #18227 holds AGENTS.md :1026+ and is not landed); needs-user-decision cleared through label-write.mjs and read back. MERGED is confirmed later by two readings (the queue ref gone + git log origin/main carrying (#18244) with one parent), then #17798's residue is stripped and #18248 (platform-readings :385–:386 turn false when this lands) is unblocked.


Generated by Claude Code

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

Labels

documentation Improvements or additions to documentation size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants