Skip to content

docs(pm-skill): record the three label-blind PR read legs, paid by two cuts - #12995

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-12902-pr-label-read-blindness
Aug 28, 2026
Merged

docs(pm-skill): record the three label-blind PR read legs, paid by two cuts#12995
os-zhuang merged 1 commit into
mainfrom
claude/issue-12902-pr-label-read-blindness

Conversation

@os-litant

@os-litantos-litant commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Fixes#12902

One fact row in .claude/skills/pm-dispatch/references/platform-readings.md, beside the
existing label-write facts (the skip-changeset / size-labeler / union-write cluster).
All three documented ways to read a PR's label set are blind — two of them silently — so a
union computed from either silent leg strips labels while every step reports success.

The row as landed

- **PR 标签的三条读腿全盲、两条静默**(2026-08-28 同日实测):① `issue_read get_labels` 传 PR 号
回「Could not resolve to an Issue」—— REST「PR 也是 issue」的惯例在此方法不成立;**响亮失败即
路由信号**,改走腿③。② `pull_request_read get` 的 `labels` **时缺时滞**:dev 席同一张新 PR 两读
整个字段缺席(非空数组),PM 席三张老 PR 三读齐备 ⇒ 连盲都不稳定,比整类缺席更险。③
payload 档:issue 页的 `href` 锚点 grep(`/labels/NAME`)在 PR 页命中**零**,PR 侧拼写是
`data-name="NAME"`(片链到 `issues?q=…label%3A…`)。⇒ **读成功而标签空/缺席 ⛔ 不读
作「没有标签」**:按 `data-name=` 确认,否则整集作 UNKNOWN、优先加法端点(可达时);⛔ 单读与
单次**即时**读回都不决断(compare-read-back 报 3 个,数分钟后再读只回 1 个,两个 auto 标签无写
入而消失)⇒ union-write 欠一次**延迟确认**;必需标签(如 `skip-changeset`)其后每次触碰重核。

Nine lines. All three dated 2026-08-28 measurements are banked in it: leg 2's two
directions (dev seat — field absent twice on a fresh PR; PM seat — present on three
established PRs) and the third measurement (a read minutes after a compare-read-back
reported three labels returned one, two auto-labels gone with no intervening write), which
is what forces the DELAYED confirm into the operative rule.

Net 0 at the 314-line ceiling — cut ledger

The file's ratchet ceiling is 314 with zero headroom, so the nine new lines are paid for by
nine cut lines. No re-wrap line-buying: both cuts remove whole bullets.

CutLinesSurviving home
The issue_read / get_labels PR row3The new row itself. Its loud half is carried forward verbatim — the Could not resolve to an Issue string, the note that REST's "a PR is an issue" convention does not hold for this method, and the loud-failure-is-a-routing-signal reading. Its remedy (「PR 的标签读数走 pull_request_read get(labels 随响应回来)」) is precisely what this card's measurement falsifies, so it is corrected rather than lost.
The refs/remotes/origin/main shared-ref row6AGENTS.md §9, which carries it more fully — the four isolated ref namespaces stated exactly (the cut copy said only 工作树与 HEAD), the "staged on arrival" hazard, the FETCH_HEAD-is-per-checkout corollary, and the BASE=$(git rev-parse HEAD) practice — and .claude/agents/os-dev.md 「标准条款」家族规则, which carries the dev-facing half verbatim including the git reset --soft origin/main spelling and the four-agent measurement. CLAUDE.md inlines the worktree-isolation half. It is also a local-git fact rather than a GitHub API/tool reading, which is what this table's own header scopes it to.

One provenance detail is deliberately dropped: leg 1's earlier 2026-08-27 两个 dev 独立实测
date. It is superseded, not lost — leg 1 was reproduced twice on 2026-08-28 (~2 minutes
apart, ruling out creation lag) and the row carries that date with the error string intact.

Gate verdicts

Union derived mechanically, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (8 families matched from the change set the script derives
itself). Re-run after the final commit and green on it — all figures below are from
d6e9dc3b3. Every exit code captured before any pipe (redirect to a file, read the file
after).

GateVerdict line it printedExit
check:pm-skill-ratchet (314 ceiling)✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/platform-readings.md is 314 lines (ceiling 314; headroom 0).0
check:pm-skill-ratchet (max-line rule).claude/skills/pm-dispatch/references/platform-readings.md: every line is within 120 bytes (or structurally exempt). — the 120-byte rule prints only on failure, so this verdict was taken positively by calling the gate's own scanLineLengths / lengthVerdict exports on the landed file rather than read off an absence.0
check:pm-skill-id-lint✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).0
check:pm-governed-prose✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces (docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md) and claim no others.0
check:skill-frame-sync✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files0
check:skill-frame-freshness✓ check-skill-frame-freshness: the decision frame in this tree is current with origin/main (fetched just now).0
check:agent-test-spellingself-test + run clean0
check:doc-authoringself-test + run clean0
check:doc-formula-expressionsself-test + run clean (needed @objectstack/formula and @objectstack/lint built first — its two earlier PREREQUISITE NOT MET exits were not measurements)0
check:pm-governed-mergesself-test + run clean0
check:nul-bytesclean; plus a direct control-byte scan of the edited file, no match0
check-governed-queue-guard.mjs⛔ … could not read GITHUB_EVENT_PATHNOT MEASURED locally, not red. It reads the workflow event payload and nothing else, so it is CI-owned; it exits non-zero rather than green when it cannot look, by design.1 (not a measurement)

Everything ran through scripts/pm/os-verify-lock.sh on slot issue-12902-skills
(VERDICT command-exit 0 · held the lock 17s · waited 0s on the final pass).

Delivery

Draft, base main, docs-only. Not flipped ready, no reviewers requested, no auto-merge —
the PM runs the four-piece. Authored in session
https://claude.ai/code/session_01MnijPVVDakqK2J335JoJtq (recorded here as prose because a
body PATCH downgrades the session-form footer to the bare form).

skip-changeset was applied at open through the MCP fallback, running the exact protocol
this row lands — and the run reproduced the card's near-miss live, with the legs swapped:

  • Web-payload read (leg 3) on this PR, minutes after creation: ZERO labels. No label
    chips in the HTML, and the PR page's embedded JSON carries no labels array at all (four
    JSON blocks scanned) — unlike an issue page. A data-name= grep on a PR page whose body
    documents that spelling also matches the body text, so the grep must be scoped to the
    chip markup or it reads its own documentation back.
  • pull_request_read get (leg 2) at the same minute: documentation, size/s
    populated, and correct.
  • A union computed from the web read alone would have been {skip-changeset} and the
    whole-set replace would have stripped both auto-labels. The union actually written was
    {documentation, size/s, skip-changeset}.

So on this PR the silent leg was leg 3 and leg 2 was the sound one — the reverse of the
dev-seat run the row records. That is the row's point restated by a third instance: the
blindness is not stable per leg, which is why the rule is "empty is not a reading" rather
than "prefer leg N". Comparative read-back and a delayed confirm follow in the report on
the card.

Generated by Claude Code

…o cuts
All three documented ways to read a PR's labels are blind, two of them
silently: get_labels cannot resolve a PR number (loud), pull_request_read's
labels field is intermittently absent or stale, and the issue-page anchor grep
matches zero on a PR page. A union-write computed from either silent leg
strips labels while reporting success, so the row carries the operative rule:
an empty/absent label reading is not a reading of "no labels", and neither a
single read nor a single immediate read-back is decisive.
Net 0 at the 314-line ceiling, funded by two cuts with surviving homes: the
superseded get_labels row (its loud-failure half is carried forward into the
new row; its remedy is what this measurement falsifies) and the shared
remote-tracking-ref row (AGENTS.md carries it more fully, and
.claude/agents/os-dev.md carries the dev-facing half verbatim).
Co-Authored-By: Claude <noreply@anthropic.com>
@os-zhuang
os-zhuang marked this pull request as ready for review August 28, 2026 13:27
@os-zhuang
os-zhuang enabled auto-merge August 28, 2026 13:27
@os-zhuang
os-zhuang added this pull request to the merge queueAug 28, 2026
Merged via the queue into main with commit 1637d66Aug 28, 2026
32 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-12902-pr-label-read-blindness branch August 28, 2026 14:10
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude