You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[finding] os-dev.md tells every agent the label write IS a whole-set PUT — the additive POST endpoint exists and was measured working from an agent seat #10902
.claude/agents/os-dev.md:272-273 tells every dispatched dev agent that the label write is a whole-set PUT, and prescribes read → union → write as the way to survive it:
打标签是你的步骤、不是 CI 的,PR 一建立就打;先读回、再写并集——标签写入是整组 PUT(裸集合会抹掉机器人刚打的标签,CI 的写入也可能抹掉你的;changeset 门的首轮可能与你的写入竞态)
The premise is false. GitHub's REST API has an additive endpoint that adds labels without touching the ones already there:
POST /repos/{owner}/{repo}/issues/{n}/labels -d '{"labels":["skip-changeset"]}'
There is no union to compute, no read-back race to lose, and nothing a bot applied a second earlier can be erased by it.
Measured today, from an agent seat, not from the PM seat
An os-dev agent ran two authorized read-only probes with Authorization: Bearer $GITHUB_TOKEN:
request
status
GET https://api.github.com/rate_limit
200
GET https://api.github.com/repos/objectstack-ai/objectstack/issues/10896/labels
200
The second is the exact read half of the additive flow, against the same endpoint the write uses, differing only in verb. So curl reaches api.github.com with working credentials from inside an os-dev seat. (gh is genuinely absent everywhere in this container — command -v gh exits 1 — which is a separate fact and not the reason.)
Two independent occurrences in one session
Both agents did exactly what os-dev.md tells them to, and both flagged it against the PM's brief:
Neither lost a label — the timelines for #10896 and #10900 both show zero unlabeled events. The procedure works. It is just doing by hand, with a race, what one call does atomically.
⭐ The part that makes this worth a card rather than a note
The PM seat has been writing an unconditional "never write labels as a whole set" into every dispatch brief, which directly contradicts the document those agents are bound by. An agent obeying os-dev.md violates the brief every time; an agent obeying the brief has to work out on its own that curl is available, because neither document names a mechanism. Two agents in one session hit that gap and resolved it differently, and both had to spend a paragraph explaining themselves.
That is the PM's error as much as the file's, and it is stated here rather than quietly fixed in future briefs so the contradiction is on the record.
Why the workaround is not merely redundant
os-dev.md's own parenthetical names the cost it cannot avoid:
CI 的写入也可能抹掉你的;changeset 门的首轮可能与你的写入竞态
Read → union → write loses to any writer that lands between the read and the write. The additive POST has no such window. The doc then says the step is closed by the read-back, not the write — which is a way of detecting the race after the fact, not of avoiding it. So this is not style: the sanctioned procedure is strictly less safe than the call it stands in for, for the exact failure mode #5533 is about.
Suggested shape — ⛔ not a PR from this seat
.claude/agents/os-dev.md is governed, human-merge-only. Filing rather than editing.
What the paragraph would need:
State that the additive POST /issues/{n}/labels is the mechanism, and name it concretely enough to be executable (the curl line above), since "apply it additively" alone was demonstrably not actionable from an agent seat.
Keep read-back as the closing step — that part is right and both agents used it well.
Keep the whole-set read → union → write as an explicitly declared fallback for a seat where the additive call is refused, with the requirement to report the read-back. It should not be the default, and it should not be described as what the write "is".
Leave the objectui half untouched — that the skip-changeset label does not exist there, and must never be created, is unrelated and correct.
Filed unassigned by the domain:devx PM seat (#6023). Observation class: the mechanism, its measurement, and the contradiction it produced.
Refs: #5533 (the whole-set PUT erasing bot labels) · #10703 / PR #10777 (the same verb in pr-automation.yml) · #10778 (nothing gates the verb) · #10880 / PR #10896 and #10793 / PR #10900 (today's two occurrences)
What
.claude/agents/os-dev.md:272-273tells every dispatched dev agent that the label write is a whole-set PUT, and prescribes read → union → write as the way to survive it:The premise is false. GitHub's REST API has an additive endpoint that adds labels without touching the ones already there:
There is no union to compute, no read-back race to lose, and nothing a bot applied a second earlier can be erased by it.
Measured today, from an agent seat, not from the PM seat
An os-dev agent ran two authorized read-only probes with
Authorization: Bearer $GITHUB_TOKEN:GET https://api.github.com/rate_limitGET https://api.github.com/repos/objectstack-ai/objectstack/issues/10896/labelsThe second is the exact read half of the additive flow, against the same endpoint the write uses, differing only in verb. So
curlreachesapi.github.comwith working credentials from inside an os-dev seat. (ghis genuinely absent everywhere in this container —command -v ghexits 1 — which is a separate fact and not the reason.)Two independent occurrences in one session
Both agents did exactly what
os-dev.mdtells them to, and both flagged it against the PM's brief:check:type-check-coveragehas no invariant for a tsconfigincludethat names a GENERATED directory the package'stypecheckscript never generates #10880 / PR feat(gate): GENERATED_COVERED — a tsconfig include rooted in a generated path must be produced by the typecheck script, or declared as deliberately not produced #10896 — usedmcp__github__issue_writewith alabelsarray. That tool's array is the whole-set PUT. It reported the whole-set write as the only mechanism available; the two 200s above later showed that claim was an untested inference, which the agent withdrew.codeOnlybut still nottypeDeclRegions— a literal-unionroute:TYPE member still mints a silent phantom row #10793 / PR fix(devx): read the ledger row recognizer through typeDeclRegions too #10900 — read['documentation','size/m'], wrote the union['documentation','size/m','skip-changeset'], read back and confirmed both bot labels survived. Its words: "no additive-label tool in its MCP set, so I used the standing fallback in my own instructions."Neither lost a label — the timelines for #10896 and #10900 both show zero
unlabeledevents. The procedure works. It is just doing by hand, with a race, what one call does atomically.⭐ The part that makes this worth a card rather than a note
The PM seat has been writing an unconditional "never write labels as a whole set" into every dispatch brief, which directly contradicts the document those agents are bound by. An agent obeying
os-dev.mdviolates the brief every time; an agent obeying the brief has to work out on its own thatcurlis available, because neither document names a mechanism. Two agents in one session hit that gap and resolved it differently, and both had to spend a paragraph explaining themselves.That is the PM's error as much as the file's, and it is stated here rather than quietly fixed in future briefs so the contradiction is on the record.
Why the workaround is not merely redundant
os-dev.md's own parenthetical names the cost it cannot avoid:Read → union → write loses to any writer that lands between the read and the write. The additive POST has no such window. The doc then says the step is closed by the read-back, not the write — which is a way of detecting the race after the fact, not of avoiding it. So this is not style: the sanctioned procedure is strictly less safe than the call it stands in for, for the exact failure mode #5533 is about.
Suggested shape — ⛔ not a PR from this seat
.claude/agents/os-dev.mdis governed, human-merge-only. Filing rather than editing.What the paragraph would need:
POST /issues/{n}/labelsis the mechanism, and name it concretely enough to be executable (thecurlline above), since "apply it additively" alone was demonstrably not actionable from an agent seat.skip-changesetlabel does not exist there, and must never be created, is unrelated and correct.Filed unassigned by the
domain:devxPM seat (#6023). Observation class: the mechanism, its measurement, and the contradiction it produced.Refs: #5533 (the whole-set PUT erasing bot labels) · #10703 / PR #10777 (the same verb in
pr-automation.yml) · #10778 (nothing gates the verb) · #10880 / PR #10896 and #10793 / PR #10900 (today's two occurrences)Generated by Claude Code