docs(agents): the comment rule exempts a verbatim maintainer ruling preserved as a quotation block - #18315
Conversation
…reserved as a quotation block AGENTS.md's comment rule gains one closed exemption beside the reporting one: a verbatim maintainer ruling preserved as a quotation block. The sentence lands in place in the Commit message sentence group at the 1075-line ceiling; the restated clause about the pair staying model-free is the payment (the group's first sentence and the pre-push hook already say it), and every line stays within the 120-byte width rule. No probe in the tree reads prose for model identifiers: the pre-push gate judges the trailer value only, the Served-tier readers judge one token, the agent-model gate reads frontmatter pins, and the H64 row keys on session ids. So no probe changes. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr
…ents-md-quotation-exemption
Contract reviewServed-tier: Reviewing seat: ① Derived judgments
② Semver levelNot applicable — nothing published moves; ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
维护者速读(终稿)— PR #18315 / #18092改了什么:AGENTS.md 第 442–444 行的评论规则加一句闭合豁免——「逐字保存为引用块的维护者裁决」不算违规;席位自己在正文里写的型号仍算违规(第一句未动)。措辞照总监席裁决 A 的原文;行数 1075 不变,代价是删掉了一句重复的「the pair stays model-free」(第 440、442 行已各说一遍)。 为什么没有改探针:dev 逐个测过仓内所有可能读型号的代码——commit trailer 门、pre-push hook、agent 定义 要你做的:审 PR #18315 的措辞与位置(裁决说了由你在 review 时改),同意即 APPROVE;之后由本席按裁定 C 落地。若你想把「原话照抄不译」四字也写进句子,需要把 AGENTS.md 上限抬 1 行(现 1075/1075),那是你的裁定。 其他:席位派发前提有两处被 dev 证伪(AGENTS.md 散文行也受 120 字节宽度限制;同段无可删行),已记入记录 5684207107。 Generated by Claude Code |
|
Maintainer reply on record (director seat, 2026-09-15T23:56Z): batch #138 presented this PR as a governed draft row — the verbatim-quotation exemption in the comment rule (batch #136 item 1, A) — as is, no ceiling raise — with the skills seat's in-seat contract review PASS on the current head and 「一个动作:Approve」; the maintainer answered 「138 同意」. Review is already requested from Generated by Claude Code |
|
Ruling-C landing provenance — skills seat, session Generated by Claude Code |
… skip is not a failure, and a check reports the skips outside the declared roster (objectstack-ai#18357) Fixes objectstack-ai#18308 ## What `.claude/skills/pm-dispatch/SKILL.md` :629 read 「入队资格 = PR 上每一个 check 全绿,⛔ 不是 required 子集;required 集是队列强制的地板。」 — a bar no landing on this repository can satisfy, because `skipped` is the ordinary conclusion of a path-filtered job and the charter defined no state for it. Measured over the ten most recent landed heads (below), every head carried 8–19 skipped check-runs beside its successes; the seat's landings read 「success = green, skipped = not failed」 by an unstated convention. Two changes, both inside the claimed file surface: 1. **SKILL.md :629, re-keyed in place** (112 B → 119 B, ≤120 B; 812 → 812 lines; no issue number): > `- 入队资格 = 每个 check 为 success 或预期 skip(名单:check-expected-skips.mjs),⛔ 不是 required 子集。` The bar now names the two states a check may be in — `success`, or an expected skip — and points at the one machine-readable roster of expected skips. The third clause of the old line (「required 集是队列强制的地板」) did not fit the byte ceiling and is carried by AGENTS.md §7 (「the queue enforces only the required set」); the ⛔ clause is kept verbatim. 2. **`scripts/pm/check-expected-skips.mjs`** (new; `package.json` gains `check:pm-expected-skips` = its `--self-test`): given `--pr N` or `--head SHA` (or a pre-fetched payload via `--check-runs-json FILE|-`), it reads the head's check-runs and judges every `skipped` run against a roster declared once, in the file, as data with a one-line reason per row. Exit register: **0** every skip is in the roster · **4** a skip is outside it (each named and classified: a filter miss, or a dependency skip when the same check suite holds a failed run; a raw `matrix` template in the name is read as "skipped before matrix expansion, i.e. a job-level gate — never a workflow-level `paths:` filter, which creates no check-run at all") · **3** NOT MEASURED (unresolvable sha, 404, network, no check-runs on the head, or a check-run still running — the skip set is not final). Report-only; the self-test pins structurally that the file carries no `method:` key and imports no writer. The roster is **tied to the workflows, not remembered**: `--self-test` parses each row's workflow with the `yaml` package and asserts the job exists, carries the row's name, carries an `if:`, that the `if:` spells the declared gate (`needs.filter.outputs.X != 'false'`, the `github.event.action` exclusion, or the label literal), and — for ci.yml rows — that the `filter` job's output keeps its `|| 'true'` widening, which is what makes "the merge-queue build runs it" true. The audit is driven red in the self-test on a deleted, renamed, un-gated and re-gated job, a lost widening and an unreadable workflow. ## The roster (11 names), measured over ten landed heads | name | workflow › job | mechanism | over the ten heads | |---|---|---|---| | `Build Core` | ci.yml › build-core | `filter` output `core` said false; REQUIRED context, judged on the queue build | skipped 10/10 | | `Temporal Conformance (live PG + MySQL)` | ci.yml › temporal-conformance | same, REQUIRED context | skipped 10/10 | | `Dogfood Regression Gate (${{ matrix.shard }}/3)` | ci.yml › dogfood | same; raw matrix template = pre-expansion name (the aggregate `Dogfood Regression Gate` runs `if: always()`, never skips) | skipped 10/10 | | `Dogfood Verify CLI` | ci.yml › dogfood-verify | same | skipped 10/10 | | `Test Core (${{ matrix.shard }}/6)` | ci.yml › test | `core` OR `crosspkg` both false (scripts/** is in `crosspkg`, so scripts/pm heads RUN it) | skipped 3/10 — only the .md-only heads | | `Build Docs` | ci.yml › build-docs | `filter` output `docs` | skipped 10/10 | | `Console Pin Gate` | ci.yml › console-pin | `filter` output `console` | skipped 10/10 | | `Check PR Size` | pr-automation.yml › pr-size | `if:` excludes `labeled` / `unlabeled` / `edited` events; each event is its own run on the same head | skipped 9/10, success beside it 10/10 | | `Auto Label` | pr-automation.yml › auto-label | same | skipped 9/10, success beside it 10/10 | | `Check Changeset` | pr-automation.yml › changeset-check | `if:` skips a PR carrying `skip-changeset` | skipped 10/10 (every head carried the label), success beside it 9/10 (the run before the label) | | `Packed-tarball smoke (opt-in)` | pack-smoke-optin.yml › pack-smoke | opt-in by `needs:pack-smoke` | skipped 10/10 | Never skipped on any of the ten heads (and carrying no `if:`): `Lint & Repo Gates`, the four `Type Check ·` lanes, `TypeScript Type Check`, `Test Core` and `Dogfood Regression Gate` (the aggregates), `Governed Surface Queue Guard`, `filter`, the four claim/keyword guards, `Check Documentation Links`, `Close issues referenced in other repositories`. Workflows with a workflow-level `paths:` filter (`half-state-patrol.yml`, `board-snapshot.yml`) produce no check-run at all on a non-matching head — they are absent on 6 of the ten heads, never `skipped` — which is the measured basis for the "a skipped check-run is never a `paths:` filter" reading. ## Reverse verification (all at `7a1f99ea`) | leg | result | |---|---| | `--head` on the ten landed heads objectstack-ai#18298 · objectstack-ai#18307 · objectstack-ai#18311 · objectstack-ai#18315 · objectstack-ai#18316 · objectstack-ai#18322 · objectstack-ai#18326 · objectstack-ai#18327 · objectstack-ai#18328 · objectstack-ai#18332 | **exit 0 on every one**; accepted skips per head: 11 · 12 · 11 · 19 · 12 · 8 · 11 · 18 · 18 · 11, every name in the roster; e.g. objectstack-ai#18322 (the 8-skip head): `Build Core`, `Build Docs`, `Check Changeset`, `Console Pin Gate`, `Dogfood Regression Gate (…/3)`, `Dogfood Verify CLI`, `Packed-tarball smoke (opt-in)`, `Temporal Conformance` | | constructed fixture: the real objectstack-ai#18322 payload with `Lint & Repo Gates` mutated to `skipped` | **exit 4**, naming `Lint & Repo Gates (check suite 94780297729)` and classifying it `filter-miss` | | garbage sha `--head deadbeef…deadbeef` | **exit 3** — `NOT MEASURED — HTTP 422 — the API cannot resolve that sha` | | `--pr 18315` (the head is looked up through the proxy) | exit 0, `19 skipped check-run(s), every one in the roster`; `--pr 18308` (an issue number, not a PR) → exit 3 (HTTP 404) | | `--self-test` | 99 cases pass, offline (the roster's truth on the live workflows and its audit driven red six ways; the judge on the measured 39-run objectstack-ai#18315 head and on fixtures for 0 / 4 / 3; read classification; argv; the real CLI on payload files incl. `--json`; the structural pins) | | SKILL.md ratchet | `wc -l` 812 → 812; :629 112 B → 119 B; `check-skill-line-ratchet: SKILL.md is 812 lines (ceiling 812; headroom 0)` | ## Gates (local, at `7a1f99ea`) `node scripts/pm/dispatch-gates.mjs --commands .claude/skills/pm-dispatch/SKILL.md scripts/pm/check-expected-skips.mjs package.json` derived 45 commands; all 45 were run with the exit captured by redirect, and `--ran` reconciles: `✓ dispatch-gates --ran: 45 derived famil(ies) accounted for — 40 run, 5 NOT-MEASURED (5 DERIVED from a recorded exit 3)`. The five NOT MEASURED are the `dist/`-reading families on an unbuilt tree (`check:dts-closure`, `check:dual-build-cjs-loads`, `check:lean-entry-closure`, `check:sourcemap-no-sources-content`, `@objectstack/lint check:doc-formula-expressions` — each prints `PREREQUISITE NOT MET`); this diff touches no package, so no build closure is owed locally and CI runs them built. The `pnpm check:pm-dispatch-gates` battery was not derived, so it was not run. Named gates, verdict lines quoted: `check-skill-line-ratchet: SKILL.md is 812 lines (ceiling 812; headroom 0)` · `check-skill-id-lint: 27 file(s) clean` · `check-skill-frame-sync: the one declared copy of the decision frame is internally coherent` · `check-self-test-wired: every one of the 212 script(s) CI runs that ship a --self-test has that self-test run by CI` (the new script is not in that population — see Acceptance notes) · `check-nul-bytes: OK (scanned 8707 text file(s))` · `check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces` · ESLint (`--no-inline-config`) on the new file: exit 0 · `check-governed-merges.mjs --test .claude/skills/pm-dispatch/SKILL.md`: **GOVERNED** (`.claude/**` ×1), exit 3 as designed. `check-clause2-carriers.mjs --pair` is run once this PR exists and its reading goes in the report comment. ## The one design choice, on the four axes: a roster declared in the check vs. deriving expectedness live from the workflows' `paths` filters - **实际业务需求** — the measured need is name-level: 31 landings this shift and the ten heads above were judged by "is this skipped name one that always skips?", and zero of them needed a diff-level answer. The diff-level question ("should `Build Core` have run on THIS diff?") is already answered for the required family by the platform: on `merge_group` ci.yml's `filter` widens every output to `'true'` (the `|| 'true'` half of the filter contract, now pinned by this check's self-test), so the family runs on the merged tree before `main` moves. A live derivation would answer a question nobody measured a need for, at the cost below. - **项目长远合理性** — a roster is a declaration that can rot; a live derivation is a second evaluator of the platform's own semantics (dorny/paths-filter's picomatch dialect, GitHub's expression language, matrix name templates, per-event runs) that can drift from the real evaluator. Both are drift; the roster's drift is made LOUD here (every row is pinned to its live job, name, `if:` and gate spelling — a rename or re-gate reddens CI), while an evaluator's drift is silent by construction (a wrong glob yields a confident "expected"). Contract-first: the workflow file is the contract, and the roster is a checked reading of it, not a copy of its path lists. - **防 AI 写代码犯错** — the roster makes the wrong move structurally hard: a new gated job's first skip is exit 4 until someone adds a row WITH its mechanism, and a row that names a job the tree does not gate is red. A live evaluator is where an AI would quietly mis-implement glob semantics and produce the false green this tree refuses everywhere else (the "could not read" ≠ "clean" class). The declared-vs-delivered line is kept: the check advertises the name question only, and says so in its header and report. - **创业阶段不扩散需求** — the roster is ~11 rows of data and one audit; live derivation is a YAML-expression evaluator with parity tests against GitHub. No pull exists for the latter; if a rostered required job is ever found skipped on a diff inside its filter, that measurement is the card that would justify it. **Recommendation: the roster in the check (implemented).** Should the seat prefer live derivation, nothing here blocks it — the roster rows already carry `workflow`, `job` and the gate's outputs, which is the input a derivation would start from. ## Acceptance notes - **Self-test wiring.** `check:pm-expected-skips` exists in `package.json` (mirroring the report-only siblings), but no workflow names it and lint.yml was outside this card's file surface, so `check-self-test-wired` (correctly) does not count it and CI does not run its 99 cases. The completion is one lint.yml step beside the other `check:pm-*` steps (`run: pnpm check:pm-expected-skips`); left to the seat — 承接者:the skills seat, on this PR or a sibling. Noted, not filed. - **:629's floor clause dropped for the byte ceiling** (「required 集是队列强制的地板」); AGENTS.md §7 carries the fact. Noted, not filed. - **Exit 4 judges skips only.** Other conclusions on the head (`failure`, `cancelled`, `neutral`, …) are printed loudly under `other conclusions` and do not move this check's exit; the bar's success half is read from the same listing. A malformed `--head` (non-hex) is a usage error (exit 2), a well-formed sha the API cannot resolve is exit 3. Noted, not filed. - **The card's five-name family was a subset.** The measured recurring family is eleven names (six ci.yml `filter`-gated jobs the card did not list, including two REQUIRED contexts); the card's citation of a "platform-readings discipline (a skip is not a pass)" has no verbatim carrier — the nearest lines are AGENTS.md §7 (「Green means the gate-carrying jobs' conclusion is success」) and `references/review-checklist.md:43`. Recorded in the report, no card. - objectstack-ai#18349 is not addressed here; it holds :513 / :523 of the same file (region-level parallel). `origin/main` did not move under this branch after cut (`ceb6b5fb`). ## 维护者速读(草稿) **改了什么**:入队资格这一行改成「每个 check 为 success 或预期 skip」,并新增一个只读的检查脚本 `scripts/pm/check-expected-skips.mjs`:给它一个 PR 号或提交 SHA,它读出该提交上所有 check,凡是 `skipped` 的都对照脚本内声明的「预期 skip 名单」(11 个名字,每个带一句为什么会 skip 的机制),名单外的 skip 会被点名并退出码 4;读不到就退出码 3,绝不当作通过。 **为什么改**:原来的「每一个 check 全绿」在本仓库任何一个 PR 上都做不到——路径过滤的 job 本来就以 `skipped` 结束,实测最近十次落地每次都有 8–19 个 skip。席位一直靠「记得哪些通常会 skip」在判断,而真正要分辨的是「预期 skip」与「本该跑却没跑」。现在名单是机器可读的,并且自测会把名单逐条对照真实 workflow 文件校验(job 存在、名字一致、带条件、条件拼写一致),名单不会悄悄过期。 **风险与代价(含回滚)**:规则层只改一行(≤120 B、行数 812 不变);脚本只读不写、不接入任何门禁,CI 不因它变红。名单是名字层面的判断,不回答「这个 diff 是否本该触发某个 job」——必查项由合并队列在合并树上全量重跑兜底,这一点写在脚本头部。回滚 = revert 本 PR。 **席位意见**:(留空,席位定稿) **你要做的**:本 PR 触及 `.claude/**`(规则层),需要你的 APPROVED;之后由席位落地。是否把该脚本的自测接进 lint.yml(一行 `pnpm check:pm-expected-skips`)由席位决定,本 PR 未动 lint.yml。 --- _Generated by [Claude Code](https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr)_ Co-authored-by: Claude <noreply@anthropic.com>
Fixes #18092
What this PR does
AGENTS.md's comment rule (the Commit message: sentence group, :440–:444) gains the one closed exemption ruled on the card, in place, at the 1075-line ceiling. No probe changes, because none reads prose for model identifiers (measured below). The diff is four lines ofAGENTS.mdand nothing else.Landing: this is the rules layer, so this PR is a draft and stays one until an authorized APPROVED review; the owning seat lands it afterwards. Per ruling C on #17971, no seat readies, queues or arms it, and this dev requests no reviewer.
skip-changeset: nothing published moves.The ruling (comment 5682890409, letter A, quoted verbatim and untranslated)
The sentence (before → after,
AGENTS.md:440–:444)Before (five lines, 77 / 107 / 111 / 104 / 113 bytes):
After (five lines, 77 / 115 / 116 / 119 / 110 bytes; :440 byte-identical, :441–:444 reflowed within the same five lines):
The exemption phrase is the ruling's own wording. The maintainer edits wording and placement at review — nothing here is polished beyond the ruling.
Why in place, and what paid for it (the breach the dispatch asked me to stop on)
The dispatch's route was "extend :443–:444 in place; a long line is legal there (14 lines already exceed 120 chars)". Measured:
pnpm check:pm-skill-ratchetapplies a 120-byte width rule to every ceilinged file,AGENTS.mdincluded, and the 14 over-width lines are all table rows or the one blockquote — structurally exempt classes. A prose line over 120 bytes goes red (lengthVerdict, silent on pass). So the sentence had to fit five lines of at most 120 bytes each. Byte math (greedy wrap, code spans as atoms): the group's usable capacity is 77 + 4×120 minus wrap loss; every wording that also kept the clause "the pair stays model-free" and the 「原话照抄不译」 parenthetical needed a sixth line (the tightest such wording overflowed by exactly the 27-byte parenthetical). No line in the paragraph says nothing the new sentence does not, so the "paid line in the same paragraph" route had no candidate.What paid: the deletion of the restated clause "the pair stays model-free;" — :440 already says the commit "ends with the model-free trailer pair" and :442 says "the pre-push hook refuses a model identifier in that pair", so the clause restates the sentence group's own first sentence and its hook. Content deletion is the ratchet's only legal currency; no line was folded to buy one (line count 1075 → 1075, and the reflow of :441–:444 frees nothing). The 「原话照抄不译」 act-name is carried here and on the card rather than in the sentence; the maintainer may prefer it in the sentence, in which case the ceiling needs a ruled +1 (the ratchet's
CEILINGSentry forAGENTS.mdhas precedent for a ruled raise) — that is the maintainer's call, not this dev's.The probes — measured; none reads prose for model identifiers, so none changes
scripts/check-commit-card-trailers.mjs(:848 iterates four id literals in its self-test)MODEL_ID_FORMon the trailer value.githooks/pre-pushscripts/check-agent-model-declared.mjsmodel:key of.claude/agents/*.md; amodel:mention inside description prose is pinned as NOT a declarationscripts/pm/check-clause2-carriers.mjs(isModelIdentifierToken)Served-tier:token of a review-of-record comment; header: 「What a seat writes AFTER the token is its argument, which this file does not read」scripts/pm/check-governed-queue-guard.mjsServed-tier:token through the clause-2 predicatescripts/pm/check-half-states.mjsH64session_id (h64SpeaksAbout= seat signature present AND no session id)scripts/pm/check-half-states.mjsH65 (merged fromorigin/mainat10a7b9faduring this PR).claude/hooks/*,packages/lint/scripts/*,.github/workflows/*.claude/skills/pm-dispatch/**and.claude/agents/**for 型号 / 探针So the ruling's probe half has no in-tree target: the seat's own ad-hoc greps were the only "型号探针", and they are not repository code. A self-test case "a quotation block carrying an identifier is not counted; a seat-prose identifier still is" has nothing to attach to without inventing a new prose scanner, which would be scope the card does not carry.
Quotation form (measured on the protocol and the live seat posts)
The protocol names the act as 裁决引文照抄不译 (
.claude/skills/pm-dispatch/SKILL.md:100;references/core-rules.md:26) andAGENTS.mdCommunication says 「引用中文裁决时保持原文、不翻译」. On the live posts, every identifier-carrying preserved ruling is a 「…」 corner-bracket span inside prose labelled 原话照抄不译 / 逐字 / verbatim — #6015 L128 and L130, #6021 L24, L34 and L136 — and zero are Markdown blockquotes (> …); the 47 blockquote lines in #6015 are the seat's own correction notes, #6021 and #7623 carry none. The ratchet's own exemption classes already recognise both shapes as verbatim maintainer rulings (quotation= a multi-line 「…」/『…』 ruling;blockquote= 「Every blockquote in this corpus is a verbatim maintainer ruling」). The sentence pins the ruling's letter, "a quotation block", and this PR pins no narrower form in code because no code reads one.Verification
b671f83bbynode scripts/pm/dispatch-gates.mjs --commands(14 families, identical to the derivation ondc3d1c16):check-closing-keyword-parity(+--self-test),check-comment-mask-corpus,check:agent-test-spelling,check:docs-audit-scope,check:driver-memory-census,check:nul-bytes,check:pm-governed-merges,check:pm-governed-prose,check:pm-skill-id-lint,check:pm-skill-ratchet,check:refd-timer-probe,check:required-contexts,check:watch-hint-literal— all exit 0;--ranreconciliation: 「14 derived famil(ies) accounted for — 14 run, 0 NOT-MEASURED」.pnpm check:pm-skill-ratchet: 「AGENTS.md is 1075 lines (ceiling 1075; headroom 0)」, no width offender;check:pm-skill-id-lint: 27 files clean;node scripts/check-self-test-wired.mjs: exit 0. The batterycheck:pm-dispatch-gateswas not derived and was not run; no.mjswas touched, so no ESLint run is owed.dc3d1c16, whoseAGENTS.mdblob98e7cd4ais the merge commit's blob too): base blob7c7a5eeerestored withgit restore --source=BASE(on-disk hash proven equal) → the sentence count reads 0 and the restated clause reads 1, ratchet exit 0 at 1075 lines; HEAD blob restored withgit checkout HEAD -- AGENTS.md(hash proven equal),git diff HEADandgit status --porcelainboth empty; restore trap on EXIT/INT/TERM. On HEAD the sentence count reads 1 and the restated clause reads 0.Acceptance notes
AGENTS.mdis false under the ratchet's width rule; the 14 over-width lines are table rows and one blockquote. 承接者: the skills seat's nextAGENTS.mddispatch reads thelengthVerdictexemption classes before choosing "extend in place".origin/mainmoved once under this branch (feat(pm): the half-state patrol reads the tier a triage round artefact names #18311,scripts/pm/check-half-states.mjsonly); merged in, never rebased; the union was re-run on the merge commit.维护者速读(草稿)
改了什么:
AGENTS.md的评论规则句组(:440–:444)从「唯一豁免是 REPORTING」改为「两条豁免」:harness 写入的Co-Authored-Bytrailer(REPORTING:不申报为偏差;已落地历史不改写)与逐字保存为引用块的维护者裁决。行数 1075 → 1075,每行 ≤120 字节。为什么改:你在 #18092 批准了 A:座位贴按制度把你的裁决原话照抄不译,原话里若带型号,转抄不算违规;席位自己写的型号仍算。探针半边:仓库里没有任何脚本按型号扫描散文(逐一实测列在正文表格),所以没有探针要改。
风险与代价(含回滚):代价是删掉了「the pair stays model-free;」这句重述(句组首句与 pre-push hook 已各说一次),以及豁免句里没放 「原话照抄不译」 这个名字(字节装不下;若你要放进去,需要你裁一次上限 +1)。回滚 = revert 这一个提交,无发布物。
席位意见:(留空,席位定稿)
你要做的:审阅措辞与位置(你可直接改),若同意则给 APPROVED,由 skills 席落地;不同意「删重述句」的付账方式,则改裁「上限 +1」或指一行删除。
Generated by Claude Code