Skip to content

docs(agents): a claim pre-check hit is a hint, not a claim - #18827

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-18811-precheck-hit-is-a-hint
Sep 18, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-18811-precheck-hit-is-a-hint

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #18811

Clause-②: no

The defect

AGENTS.md rule 2 hands the dev git ls-remote --heads origin | grep issue-N as a one-command claim pre-check and states only what the command IS — never what a HIT MEANS. The reading rule was not missing from the repo; it was in a layer this reader is never sent to. It stands today in the fact layer, .claude/skills/pm-dispatch/references/platform-readings.md :378, while the dev agent definition .claude/agents/os-dev.md points at AGENTS.md eight times and carries the strings ls-remote and Claim: zero times. So the layer holding the rule has no reader, and the layer with the reader has no rule. The failure direction is the silent one: a stale head reads as "already claimed", a live card is skipped, and nothing goes red — and most heads are stale, because a dev container can create a remote branch but cannot delete one.

Re-derived readings

Taken in this worktree, not carried from the card or the triage.

Head census — re-taken

git ls-remote --heads origin 'refs/heads/claude/issue-*' | wc -l at 2026-09-17T22:52Z, exit 0:

reading value
claude/issue-* heads on origin 290 — and that INCLUDES this PR's own branch, so 289 pre-existing
seat census 2026-09-17T21:45Z 291
the #18774 dev's re-take 2026-09-17T21:48Z 291

⭐ The population moved DOWN by two between 21:45Z and 22:52Z (291 pre-existing, then 289 pre-existing plus this branch). Both vanished heads were headless ones. The census is a moving reading, which is itself the argument for a clause that states a direction rather than a number.

The split — re-taken on the same window the seat used

Newest 1,200 PRs, state=all, back to 2026-09-05T14:45Z; read at 2026-09-17T22:54Z:

re-derived (290 heads) seat's reading (291 heads)
head with an OPEN PR 26 26
head with a closed / merged PR, branch never deleted 8 8
head with NO PR 256 257

The two readings are the same population less the two deleted heads, plus this PR's own (PR-less at census time). Roughly 88% of hits are stale in both.

The two pointer readings on .claude/agents/os-dev.md

On a7bafc29af:

command result exit
git grep -c 'AGENTS\.md' -- .claude/agents/os-dev.md .claude/agents/os-dev.md:8 0
git grep -n 'ls-remote|Claim:' -- .claude/agents/os-dev.md no output 1
lit control git grep -c 'worktree' -- .claude/agents/os-dev.md .claude/agents/os-dev.md:9 0
git grep -n 'platform-readings' -- .claude/agents/os-dev.md one hit, :54, and only for the single-card read spelling 0

The lit control is what makes the empty reading a real absence rather than a mis-typed pattern: the same grep over the same file finds 9 hits for a word that IS there. And .claude/agents/os-dev.md :19 is the pointer itself, verbatim and untranslated:

仓库根的 AGENTS.md 有约束力,第一次编辑前先读它。

The clause

One sentence, appended to the existing sentence in the same bullet — not a new paragraph, and no second read added to the one-command pre-check. Verbatim:

A hit is a hint, not a claim — most heads carry no PR: ⛔ never skip a card on one, the `Claim:` comment decides.

112 characters / 116 bytes. It lands on rule 2 at what is now AGENTS.md :463–:464, and costs one line.

It does two things the pre-check could not do by itself: it names the wrong action (skipping a card on a hit) rather than only describing the instrument, and it names the record that DOES decide — the Claim: comment, which AGENTS.md :393–:395 already defines ("the identity record is the Claim: comment — first line beginning Claim:"). The clause therefore adds a reading, not a mechanism.

Two declared deviations from the dispatch

  1. The ratio is stated qualitatively, not dated. The dispatch asked for the measured ratio, dated. This file's own preamble governs its authoring: "A rule states what to do and what never to do, in one executable sentence; it carries no incident narrative, no ruling date or quotation, and no issue-number citation". A dated census in the rules layer is exactly the incident narrative that preamble excludes, and pnpm check:pm-skill-id-lint scans this file for the issue-number half of it. So the clause says "most heads carry no PR" and the dated census lives here, in the PR body, and in the fact layer. This also keeps the clause from rotting — the census moved twice today.
  2. No third pointer to the fact layer. AGENTS.md already points at pm-dispatch references/platform-readings.md twice, at :431 and :450, both times for exactly "the readings". A third pointer measured 2 added lines instead of 1 (and wrapped the code span across a line break), i.e. it would have cost a second retired line to restate a pointer the file already carries. The defect the card names is that the RULE was not in the reader's layer; the rule is now there.

The payment

AGENTS.md was at 1099 / 1099 — no headroom. The clause adds one line, so one line retires. No re-wrap is used as currency: the line is bought by deleting ~109 characters of content, and the surviving sentence is shorter than either line it replaces.

Retired — AGENTS.md :799–:800, two lines:

⛔ **Both roots are governed surfaces** — human-merge only, or queued under **Prime Directive #14**'s pinned-approval
path; no per-PR check holds it: the queue guard refuses an unpinned governed diff at queue time.

Now — one line:

⛔ **Both roots are governed surfaces** — human-merge only, or **Prime Directive #14**'s pinned-approval path.

Where the retired content survives, in this same file:

retired fragment survives at
"the queue guard refuses an unpinned governed diff at queue time" Prime Directive #14, :284 — "Behind it: the queue guard refuses an unpinned governed diff"
"queued under ... pinned-approval path" as a mechanism Prime Directive #14, :268–:274, which defines the approval, who may give it, and that the owning seat then lands
"Both roots are governed" Prime Directive #14, :257–:258, which enumerates .claude/** and skills/** in the governed-surface list

The surviving sentence keeps the pointer (a reader in the Skills section still learns both roots are governed and where the rule is); what retires is the restatement of the mechanism.

⛔ The ratchet's widest-row pin is untouched — no table row is edited. AGENTS.md: widest table row 768 bytes (pin 768) before and after.

ratchet before after
AGENTS.md lines 1099 (ceiling 1099, headroom 0) 1099 (ceiling 1099, headroom 0)
AGENTS.md widest table row 768 bytes (pin 768) 768 bytes (pin 768)
node scripts/pm/check-skill-line-ratchet.mjs exit 0 exit 0

git diff --stat: 1 file changed, 3 insertions(+), 3 deletions(-) — net zero lines.

The victim search the triage left

Report-only. Zero state writes — no card touched, no label, no branch deleted.

Method. All 290 claude/issue-* heads mapped to card numbers (281 distinct, 0 unparseable); the 256 with no PR in the 1,200-PR window re-checked per branch against the unbounded pulls?state=all&head=... endpoint (so the window is not a source of false "headless"); their card numbers intersected with the 518 open non-PR issues; each survivor's full comment list tested against the machine predicate CLAIM_COMMENT_MARKER = the regex at scripts/pm/check-half-states.mjs :1138, i.e. Claim: or Claimed: at line start, case-insensitive, blockquote allowed.

Population: 27 open cards carry a confirmed same-number headless head. Result: the list is NOT empty — 9 rows. Read at 2026-09-17T22:55Z–22:56Z. ⚠️ Every row may have left this state since.

card labels at read time stray head ahead_by claim in ANY spelling?
#8006 pm:on-hold domain:engine claude/issue-8006-put-roundtrip-census 0 none
#9613 pm:on-hold domain:engine claude/issue-9613-publish-gate-remeasure 0 none
#11633 tracking domain:services pm:blocking claude/issue-11633-cross-request-cache-design 0 yes — ## Claim + dispatch heading
#11663 priority:p0 security tracking domain:services pm:epic claude/issue-11663-platform-admin-reanchor-design 0 yes — ## Claim + dispatch heading
#12799 tooling domain:devx pm:on-hold claude/issue-12799-surplus-threshold 0 none
#14512 pm:queue domain:spec priority:p3 claude/issue-14512-multi-package-artifact-single-copy 0 yes — prose, "Claiming the producer half"
#15638 bug pm:queue domain:cli priority:p3 claude/issue-15638-ui-plugin-legacy-arm 0 yes — ## Claim heading, "Claimed by the os-dev seat"
#16184 bug priority:p2 pm:blocked domain:engine claude/issue-16184-schema-drift-media-column-ruled-end-state 0 none (only a triage seat's ⛔ 不认领 disclaimer)
#17676 bug priority:p2 pm:blocked domain:engine claude/issue-17676-writable-package-durability 0 none

Three readings that sharpen what this list is and is not:

  1. Every one of the nine stray heads is ahead_by: 0 — a zero-commit probe branch. By the fact layer's own two-read criterion (platform-readings.md :377: zero commits ahead AND no open PR), not one of them is in-flight work. On all nine, a pre-check hit today is false in the exact silent direction.
  2. Five are unclaimed in every spelling: Reject specs that do not round-trip through JSON at put() — the option-1 tightening deferred by #7856 #8006, finding: the shipped runtime publish gate already costs linearly in tenant object count — 506 ms per flow publish at 420 objects, before any widening #9613, [finding] The type-check debt ledger banked 118 raw errors of surplus across 4 of 31 entries — the measurement #6376 lacked when it decided a surplus must not go red #12799, driver-sql(schema-drift): during #15989's dual-encoding window a static JSON_COLUMN_FIELD_TYPES cannot serve both moved and unmoved deployments — ⚠️ the body's "reports the ruled end-state" framing is MEASURED FALSE, see comment 5588614136 #16184, A writable package created via POST /api/v1/packages is registered in memory only — it does not survive a restart, and leaves its published metadata orphaned #17676. The other four carry a claim the machine predicate cannot see (a ## Claim heading or prose) — see the finding below.
  3. This is not proof anyone was harmed. Seven of the nine are parked for reasons of their own (pm:on-hold, pm:blocked, pm:blocking, pm:epic, tracking). Only A multi-package artifact serializes its metadata twice — the flattened top level and every packages[i] body carry the same definitions #14512 and [finding] plugin-hono-server still accepts the legacy ui-plugin type that PluginSchema refuses — an unreachable arm under ADR-0049 #15638 carry pm:queue, i.e. sit in the dispatch pool — and both of those carry a non-marker claim. So the honest verdict is what the triage predicted: the instrument is wrong by default on ~88% of hits, and nine open cards sit in precisely the state where that default fires; no card is demonstrably a victim because of its stray head.

Gates

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, derived in this worktree with no hand-fed path list (change set: 1 path, AGENTS.md). Every exit code captured redirect-then-$?, never across a pipe.

# command exit
1 node scripts/check-closing-keyword-parity.mjs 0
2 node scripts/check-closing-keyword-parity.mjs --self-test 0
3 node scripts/check-comment-mask-corpus.mjs 0
4 pnpm check:agent-test-spelling 0
5 pnpm check:docs-audit-scope 0
6 pnpm check:driver-memory-census 0
7 pnpm check:nul-bytes 0
8 pnpm check:pm-governed-merges 0
9 pnpm check:pm-governed-prose 0
10 pnpm check:pm-skill-id-lint 0
11 pnpm check:pm-skill-ratchet 0
12 pnpm check:refd-timer-probe 0
13 pnpm check:required-contexts 0
14 pnpm check:watch-hint-literal 0

Reconciliation, dispatch-gates.mjs --repo objectstack-ai/objectstack --ran, exit 0:

✓ dispatch-gates --ran: 14 derived famil(ies) accounted for — 14 run, 0 NOT-MEASURED (a DERIVED zero — all 14 recorded an exit code and none of them is 3).

Named by the dispatch, outside the derived union — all exit 0:

command exit
node scripts/pm/check-skill-line-ratchet.mjs 0
pnpm check:skill-frame-sync 0
pnpm check:doc-authoring 0

Repo-wide pnpm lint (eslint . --no-inline-config) — exit 0, the FULL population, not a narrowing: 6,843 files linted, 0 errors, 0 warnings (count read from eslint's own --format json output). ⭐ Of those 6,843, zero are .mdeslint.config.mjs names neither .md nor markdown, so this diff's single file is provably outside eslint's configured surface altogether.

Control characters: grep -naP over the control-byte class on AGENTS.md → no match (exit 1), beyond pnpm check:nul-bytes above.

skip-changeset: nothing published moves. Measured, not assumed — no package in the workspace lists AGENTS.md in its files[] (0 of all package manifests), and a repo-root instruction file ships in nothing.

维护者速读(草稿)

改了什么 —— AGENTS.md 规则 2 里,给 dev 的认领前置检查命令后面加了一句话:一次命中只是线索,不是认领;大多数分支头根本没有 PR;⛔ 不要因为一次命中就跳过一张卡,真正作数的是卡上的 Claim: 评论。全文件只动这一句,外加一处为它付账的删减。

为什么改 —— 这条读法规则本来就存在,但写在 dev 从来不被指去读的那一层(pm-dispatch 的事实层)。dev 被指去读的是 AGENTS.md(dev 定义里点名它 8 次,ls-remoteClaim: 一次都没有)。结果是:有规则的那层没有读者,有读者的那层没有规则。而默认读法恰好是危险的那一侧 —— 实测 290 个分支头里 256 个没有任何 PR(约 88%),一个听话的 dev 在近九成命中上会把一张活卡读成「已被认领」而跳过,全程没有任何红色信号。本次另外跑了分诊席留下的受害者检索:9 张 open 卡此刻正处在这个状态,且它们的残留分支无一例外是零提交的探针分支

风险与代价(含回滚) —— 代价极低:纯文本、单文件、净零行(加一行、退一行),不动任何机制、不加门禁、不改那条命令本身。付账方式是删掉 Skills 一节里对「受管面排队机制」的重复叙述 —— 那段话在 Prime Directive #14 里已经原样存在(:257、:268–:274、:284),删的是重复,不是信息。棘轮 1099 / 1099 前后不变,最宽表格行 768 字节的 pin 未被触碰。全部 14 个派生门禁 + 3 个点名门禁 + 全仓 pnpm lint 均为 0。回滚 = revert 这一个 commit,无迁移、无下游依赖。

席位意见 ——

你要做的 —— 这是受管面(AGENTS.mdGOVERNED_SURFACES 内),需要您本人合并。请重点看两处:① 那句话的措辞是否就是您要 dev 读到的意思(尤其「⛔ never skip a card on one」这半句是不是过强);② 付账是否可接受 —— 即 Skills 一节保留指路、删掉机制复述这个取舍。另外报告里有两条本轮顺带测出、未在本 PR 修的发现(那条 grep 会匹配错卡号;Claim: 拼写已经漂移成 ## Claim),按协议交由席位立卡。


🤖 Generated with Claude Code

https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu


Generated by Claude Code

AGENTS.md rule 2 handed the dev `git ls-remote --heads origin | grep
issue-<n>` as a one-command pre-check and said only what the command IS,
never what a HIT means. The reading rule stood only in the fact layer
(pm-dispatch references), which the dev definition never points at, so
the layer holding the rule had no reader and the layer with the reader
had no rule. The failure direction is the silent one: a stale head reads
as "already claimed" and nothing goes red.

One clause on the existing sentence states the reading. Paid in-file:
the Skills section's restatement of the governed-surface queue mechanism
retires, since Prime Directive #14 already carries it.

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

Copy link
Copy Markdown
Collaborator Author

维护者速读(终稿)

改了什么:AGENTS.md 规则 2 里,dev 的认领前置检查命令(git ls-remote --heads origin | grep issue-<n>)后面加一句(116 字节):「A hit is a hint, not a claim — most heads carry no PR: ⛔ never skip a card on one, the Claim: comment decides.」全文件只动这一句。付账在文件内:Skills 一节把「受管面排队机制」的复述两行并成一行,删掉的那句机制(队列守卫拒绝未钉批准的受管 diff)在 Prime Directive #14 的 :284 原样存在,席位逐字核过;1099 / 1099 前后不变,最宽表格行 768 字节的 pin 未动。

为什么改:这条读法规则本来就在(platform-readings.md :378),但写在 dev 从来不被指去读的事实层;dev 被指去读的是 AGENTS.md(os-dev.md 点名它 8 次,ls-remoteClaim: 零次)。实测 290 个 claude/issue-* 分支头里 256 个没有任何 PR(约 88%),而容器建得出分支删不掉(PR #18808),所以一个照章办事的 dev 在近九成命中上会把活卡读成「已认领」而跳过,全程无红信号。本轮跑了分诊席留下的受害者检索:9 张 open 卡此刻正处在这个状态,9 个残留头全是零提交探针;其中 7 张因各自原因停放,没有任何一张能证明是「因为残留头」被跳过 —— 这是「默认就错的仪器」,不是已发生的事故,如实写。

风险与代价(含回滚):纯文本、单文件、净零行;不加门禁、不改那条命令本身;14 个派生门禁加 3 个点名门禁加全仓 lint 均为 0。回滚 = revert 这一个 commit。⚠️ 两处与派工单的偏离,dev 已申报、席位裁定接受:句子里不带带日期的比率、不另加指向事实层的第三个指针 —— AGENTS.md 自己的序言禁止规则句携带事故叙事、日期或 issue 引用,文件已两次指向 references/platform-readings.md,而比率一天之内变了两次,写进规则层只会腐烂。

席位意见:通过,按 dev 交付的原样。⚠️ 两条顺带测出的发现已由席位另立卡、⛔ 不在本 PR 修:#18830(那条 grep 没有右分隔符,grep issue-186 会命中五张别的卡)、#18831(四张 open 卡的认领写成 ## Claim 标题或散文,任何标记读法都读成未认领)。

你要做的:批准本 PR(AGENTS.mdGOVERNED_SURFACES 内,等您的字)。请看两处:那半句「⛔ never skip a card on one」的力度是否是您要的;付账取舍(Skills 一节留指路、删机制复述)是否可接受。合并后无后续动作;#18830 排在它后面。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 18, 2026 01:16
@os-zhuang
os-zhuang enabled auto-merge September 18, 2026 01:16
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit f7e5231 Sep 18, 2026
39 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-18811-precheck-hit-is-a-hint branch September 18, 2026 02:19
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/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants