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(pm-tooling): a label write reported success while silently dropping ONE label — the gate-carrying needs-user-decision, with the other two from the same call applied #15407
Filed by the triage seat (session session_01SwJQDFKe8tVit3BXQ9EfR5, seat post #6015) from R+145. Caught by the contrast read-back the skill mandates for label writes — ⛔ this was not found by looking for it.
What happened, in order, with timestamps
Working #15358 (a decision card that had to move out of the dispatchable queue):
14:31Z — contrast read-back over the lane. Labels came back ["priority:p2", "pm:queue", "domain:services"].
14:33Z — direct get_labels confirmed it: pm:queue still present, needs-user-decisionabsent.
14:34Z — get_label confirmed needs-user-decisionexists in the repo (LA_kwDOQ8CKns8AAAACuUmISQ), so this is ⛔ not a missing-label error.
14:36Z — the identical call re-issued, this time without type. Read-back immediately after: ["priority:p2", "needs-user-decision", "domain:services"] — correct, pm:queue gone.
14:52Z — re-read 16 minutes later: still correct. ⇒ ⛔ Nothing is reverting it; the label is not being stripped by an automation.
So in one call reported as success: two of three labels applied, one silently dropped, and the removal of pm:queue silently not performed. The write is normally a replacement — proven by step 5, where the same call did remove pm:queue.
Why this one is worse than a generic flaky write
needs-user-decisioncarries gate semantics. The skill states the hazard exactly: a gate label that is stripped is ⛔ not a red light, it is a green one, and it is indistinguishable from never having been applied. Here the specific consequence is that a decision card requiring the maintainer would have sat in pm:queue reading dispatchable, and any lane seat picking it up would have found a card whose two live options both change barrel-exported public types.
⚠️ ⛔ Nothing about this is specific to needs-user-decision. The same partial write on pm:dispatched / pm:queue produces a double-dispatch; on needs:contract-review it releases a Clause-② PR.
What is measured and what is not
Measured: the drop happened once, on one call, and the identical retry succeeded and held for 16 minutes.
⛔ Not measured — and each of these is a real hypothesis this observation cannot separate:
the base rate. One occurrence in nine label writes this round, which is far too small to rate, and n=1 could equally be one-in-a-thousand.
Why it is filed rather than worked around
The existing discipline already caught it — the four-step read-modify-write with a contrast read-back did its job on its first live use this round, and the repair cost one retry. So there is ⛔ nothing urgent to change, and ⛔ no rule to add: the rule exists and it worked.
What is worth recording is the evidence that the read-back is load-bearing rather than ceremonial, and the platform fact itself, which belongs in the readings table: an issue_write label call can report success having applied a strict subset of the labels, including dropping exactly the one that carries a gate. Any seat that treats an HTTP success as landing state is exposed, and 「API 200」≠「落地正确」 now has a dated instance behind it.
⚠️ For any seat that batches label writes: this failure is invisible without a per-card read-back. A sweep that writes twenty labels and reads back a count would have passed — the count was right, the membership was not.
Refs: #15358 (the card it happened on) · #15121 (the sibling list_issues labels-are-a-UNION reading) · seat post #6015 (R+145 close brief).
Filed by the triage seat (session
session_01SwJQDFKe8tVit3BXQ9EfR5, seat post #6015) from R+145. Caught by the contrast read-back the skill mandates for label writes — ⛔ this was not found by looking for it.What happened, in order, with timestamps
Working #15358 (a decision card that had to move out of the dispatchable queue):
issue_writeon [Decision]inspectStrandedRequestsnow over-reports: it keys onstatus === 'failed'while the platform gained an authoritative strand discriminator — a cascade-failed run the engine calls NOT stranded is reported as one #15358 withlabels: ["needs-user-decision", "domain:services", "priority:p2"]andtype: "Task". Returned success.["priority:p2", "pm:queue", "domain:services"].get_labelsconfirmed it:pm:queuestill present,needs-user-decisionabsent.get_labelconfirmedneeds-user-decisionexists in the repo (LA_kwDOQ8CKns8AAAACuUmISQ), so this is ⛔ not a missing-label error.type. Read-back immediately after:["priority:p2", "needs-user-decision", "domain:services"]— correct,pm:queuegone.The arithmetic of the failure
So in one call reported as success: two of three labels applied, one silently dropped, and the removal of
pm:queuesilently not performed. The write is normally a replacement — proven by step 5, where the same call did removepm:queue.Why this one is worse than a generic flaky write
needs-user-decisioncarries gate semantics. The skill states the hazard exactly: a gate label that is stripped is ⛔ not a red light, it is a green one, and it is indistinguishable from never having been applied. Here the specific consequence is that a decision card requiring the maintainer would have sat inpm:queuereading dispatchable, and any lane seat picking it up would have found a card whose two live options both change barrel-exported public types.needs-user-decision. The same partial write onpm:dispatched/pm:queueproduces a double-dispatch; onneeds:contract-reviewit releases a Clause-② PR.What is measured and what is not
Measured: the drop happened once, on one call, and the identical retry succeeded and held for 16 minutes.
⛔ Not measured — and each of these is a real hypothesis this observation cannot separate:
typealongsidelabelsis implicated. It is the one difference between the failing and succeeding calls,typetogether withlabelsand applied every label correctly (mcp: the stdio door resolves an API key with notenancyPosture— an ex-member's org-stamped key is admitted with its own unvetted claim #15348–cloud-connection: the marketplace-install route supplies notenancyPosturetoresolveAuthzContext— an ex-member's org-stamped API key is admitted #15353, The PM skill treats merging as internal and reversible — on repos where a merge publishes to production it is a release act and needs human confirmation #15364), so the simple version of that hypothesis is already falsified.POST /api/v1/approvals/requests/{id}/rejectreturns 500 while its effect lands AND strands the workflow run — three inconsistent outcomes from one call #13807 out ofneeds-user-decisionin the same few minutes, so a same-label concurrent write is ⛔ not excluded.Why it is filed rather than worked around
The existing discipline already caught it — the four-step read-modify-write with a contrast read-back did its job on its first live use this round, and the repair cost one retry. So there is ⛔ nothing urgent to change, and ⛔ no rule to add: the rule exists and it worked.
What is worth recording is the evidence that the read-back is load-bearing rather than ceremonial, and the platform fact itself, which belongs in the readings table: an
issue_writelabel call can report success having applied a strict subset of the labels, including dropping exactly the one that carries a gate. Any seat that treats an HTTP success as landing state is exposed, and 「API 200」≠「落地正确」 now has a dated instance behind it.Refs: #15358 (the card it happened on) · #15121 (the sibling
list_issueslabels-are-a-UNION reading) · seat post #6015 (R+145 close brief).