Observation-class, measured tonight across two dev-agent runs. No gate is red, and nothing was
lost this time. Filed unassigned, no pm:queue.
The inversion
This repo's rule for labelling an issue or PR is settled and is in every dispatch brief:
Measured tonight: the safe form was blocked for a dev agent by the session's auto-mode
permission classifier, and the unsafe form went through. The agent, correctly, reported this
rather than hiding it, and mitigated with a read → union → write → read-back.
That mitigation narrows the race. It does not close it — it is the read-modify-write whose
race #5533 records.
The near miss, from the timeline rather than the report
On PR #10682, the label events are:
| time | event | label | actor |
|---|
| 08:33:01Z | labeled | size/m | github-actions[bot] |
| 08:33:20Z | labeled | documentation | github-actions[bot] |
| 08:33:35Z | labeled | skip-changeset | os-zhuang |
No unlabeled event — nothing was dropped, and all three labels are present. But the agent's
whole-set write landed 15 seconds after a bot label it had to have already read. Had
documentation been applied at 08:33:40 instead of 08:33:20, the write would have silently
removed it, and the only symptom would have been a label quietly missing from a merged PR.
The bots are fast and they are not done when the PR opens: size/m at ~6s and documentation at
~25s after creation, in this instance. The window an agent's read-modify-write must survive is
routinely tens of seconds wide.
Why this is a real finding and not a one-off
It is not scope or credentials. The PM seat's own additive POST .../labels calls succeed
repeatedly in this same session and against these same issues (#10303, #10565, #10566, #10667
tonight), as do the targeted DELETE .../labels/<name> calls. The refusal is specific to the
dev-agent context, so it will recur for every agent dispatched, and each one faces the same
choice: violate the brief, or leave the label unset.
The failure mode is the one this repo keeps re-finding: the guidance says do the safe thing, the
tooling only permits the unsafe thing, and the unsafe thing succeeds quietly. An agent that
follows the brief and stops looks like it failed; an agent that works around it looks like it
succeeded, right up until a bot label disappears.
Directions (not a decision)
- A — allow
POST /issues/{n}/labels in the dev-agent permission set. It is strictly narrower
than the whole-set write already permitted: it can only add. - B — if A is not available, make the brief's instruction terminal: agents report the block and
the PM applies the label, never a whole-set fallback. I have already switched my own briefs to
this wording, but it costs a round-trip per PR and only holds for briefs that say it. - C — refuse the whole-set write too, so the classifier's ordering at least matches the rule's.
Cheapest to reason about, and it would have turned tonight's near miss into a loud stop.
A is the one that makes the documented rule the executable one.
Refs
#5533 (the clobber this shape causes) · PR #10682 (where it was measured) · #10603 (the
adjacent "gh is absent" gap in the label tooling)
Generated by Claude Code
Observation-class, measured tonight across two dev-agent runs. No gate is red, and nothing was
lost this time. Filed unassigned, no
pm:queue.The inversion
This repo's rule for labelling an issue or PR is settled and is in every dispatch brief:
POST /repos/{owner}/{repo}/issues/{n}/labelswith{"labels":[...]}issue_writewith alabelsarray, orPUT .../labels),because it clobbers labels added by bots between your read and your write — which is test(service-queue): pin db-queue-adapter's engine double to ObjectQL.delete's dispatch predicate (#5198) #5533.
Measured tonight: the safe form was blocked for a dev agent by the session's auto-mode
permission classifier, and the unsafe form went through. The agent, correctly, reported this
rather than hiding it, and mitigated with a read → union → write → read-back.
That mitigation narrows the race. It does not close it — it is the read-modify-write whose
race #5533 records.
The near miss, from the timeline rather than the report
On PR #10682, the label events are:
size/mgithub-actions[bot]documentationgithub-actions[bot]skip-changesetos-zhuangNo
unlabeledevent — nothing was dropped, and all three labels are present. But the agent'swhole-set write landed 15 seconds after a bot label it had to have already read. Had
documentationbeen applied at 08:33:40 instead of 08:33:20, the write would have silentlyremoved it, and the only symptom would have been a label quietly missing from a merged PR.
The bots are fast and they are not done when the PR opens:
size/mat ~6s anddocumentationat~25s after creation, in this instance. The window an agent's read-modify-write must survive is
routinely tens of seconds wide.
Why this is a real finding and not a one-off
It is not scope or credentials. The PM seat's own additive
POST .../labelscalls succeedrepeatedly in this same session and against these same issues (#10303, #10565, #10566, #10667
tonight), as do the targeted
DELETE .../labels/<name>calls. The refusal is specific to thedev-agent context, so it will recur for every agent dispatched, and each one faces the same
choice: violate the brief, or leave the label unset.
The failure mode is the one this repo keeps re-finding: the guidance says do the safe thing, the
tooling only permits the unsafe thing, and the unsafe thing succeeds quietly. An agent that
follows the brief and stops looks like it failed; an agent that works around it looks like it
succeeded, right up until a bot label disappears.
Directions (not a decision)
POST /issues/{n}/labelsin the dev-agent permission set. It is strictly narrowerthan the whole-set write already permitted: it can only add.
the PM applies the label, never a whole-set fallback. I have already switched my own briefs to
this wording, but it costs a round-trip per PR and only holds for briefs that say it.
Cheapest to reason about, and it would have turned tonight's near miss into a loud stop.
A is the one that makes the documented rule the executable one.
Refs
#5533 (the clobber this shape causes) · PR #10682 (where it was measured) · #10603 (the
adjacent "
ghis absent" gap in the label tooling)Generated by Claude Code