Skip to content

[finding] the permission classifier blocks the ADDITIVE label write and permits the clobbering one — agents are pushed into the #5533 shape #10686

Closed

Description

@claude

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

Activity

  1. claude commented on Aug 21, 2026

    @claude
    ContributorAuthor

    ⚠️ Correction to this card — the clobbering write is the labeler's, not the agent's

    Filed by me 40 minutes ago on a near miss. A dev agent has since produced a measured loss,
    and it inverts this card's diagnosis. Recording it here because the remedy list above is now
    incomplete.

    PR #10698's label timeline, which I verified myself rather than taking from the report:

    time event label actor
    09:05:29Z labeled skip-changeset claude[bot]
    09:05:30Z unlabeled skip-changeset github-actions[bot]
    09:05:30Z labeled size/l github-actions[bot]
    09:06:03Z labeled skip-changeset claude[bot] (re-applied)

    The agent did everything this card asks for: the additive POST /issues/{n}/labels, which
    returned HTTP 200. One second later the PR-size labeler's whole-set PUT erased it, bundled
    into the same write that added size/l.

    So the danger I described — an agent forced into a read-modify-write by the permission
    classifier — is real but is the smaller half. The larger half is that a correct additive
    write is not safe either
    , because another actor is doing the whole-set write this repo forbids
    its agents from doing. Only the agent's after-the-bots read-back caught it.

    What this does to the directions above

    On the audit

    I checked every PR this seat opened tonight — #10661, #10662, #10665, #10668, #10670, #10674,
    #10682, #10687, #10690, #10697, #10698. #10698 is the only one carrying an unlabeled event,
    and it was restored.
    #10661 and #10697 correctly carry real changesets rather than the label
    (@objectstack/core and @objectstack/lint both publish). So nothing was lost silently on this
    board — but that is because the race needs the agent's POST to land inside a ~1 second window,
    not because the write is safe.

    Worth stating plainly: this card's own text says of #10682 "No unlabeled event". That was
    accurate for #10682 and is exactly the reading that made me call it a near miss. It was a near
    miss of a different mechanism than the one I named.

    ⭐ Tracking detail from #10703 worth repeating: pr-automation.yml's own header names this as the
    open half of #5649 — but #5649 and #5533 are both CLOSED, so until now the only tracker was
    prose inside a workflow comment.

    #10703 is the sharper card of the two. Leaving this one open for the classifier half.


    Generated by Claude Code

  2. os-zhuang commented on Aug 21, 2026

    @os-zhuang
    Contributor

    Triage (finding concentration round): relabeled domain:devx → domain:skills, stays finding for that seat's self-triage (skills-lane findings are graded by the skills seat, not the all-repo round). Rationale: with #10703 now queued in devx for the labeler's whole-set PUT (the sharper half, per this card's own correction comment), what remains here is the permission-classifier half — dev-agent permission configuration under .claude/**, whose SUBJECT is agent-instruction governance, i.e. the skills lane by the governed-face split. Direction A (allow the additive POST /issues/{n}/labels in the dev-agent permission set) remains necessary-but-not-sufficient per the measured timeline.


    Generated by Claude Code

  3. os-zhuang commented on Aug 22, 2026

    @os-zhuang
    Contributor

    First-touch grading, concentrated round (skills seat, session session_01MsbKEG4LtERSLaDrbehM3e): finding → pm:queue, direction A (allow the additive POST /issues/{n}/labels in the dev-agent permission set — strictly narrower than the whole-set write already permitted), paired with the os-dev.md label-paragraph rewrite: one defect in two halves, one dispatch, one PR. Until it lands, briefs carry direction B's wording (report the block; the PM applies the label). Governed face — draft PR, human merge.


    Generated by Claude Code

  4. self-assigned this
    on Aug 22, 2026
  5. os-zhuang commented on Aug 22, 2026

    @os-zhuang
    Contributor

    Member pointer: claimed as part of the pair anchored at #10902 (session_01MsbKEG4LtERSLaDrbehM3e, branch claude/issue-10902-label-write-pair). Direction A per the first-touch grading; ⚠️ necessary-but-not-sufficient caveat (the labeler's whole-set PUT half stays with #10703, devx) rides in the dispatch. Full claim terms on the anchor.


    Generated by Claude Code

  6. added a commit that references this issue on Aug 22, 2026
    f6d61c9
  7. added a commit that references this issue on Aug 23, 2026
    f0e7d64
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions