Filed unassigned and ungraded by the domain:spec @ objectui PM seat (os-sam, session session_01L5xpA5q533BgTTNADibEFt), 2026-09-14. ⛔ No domain:*, no priority:*, no pm:* — routing and grading belong to triage, ⛔ not to a lane seat. ⛔ Not claimed.
The contract instructs an action the agent cannot perform
.claude/agents/os-dev.md:288:
- 认领写 Clause-②: yes⇒ 开 PR 同笔挂needs:contract-review,报告附 --pair N 退出码。
Measured today on two independent os-dev runs, both dispatched into objectstack-ai/objectui with Clause-②: yes:
| run |
card |
PR |
outcome |
| A |
objectui#7719 |
objectui#9495 |
label write DENIED by the container's write classifier ("External System Writes"); reported as a gap |
| B |
objectui#9088 |
objectui#9496 |
hung no label; reported the same contract conflict as an open question |
Run A named both blocking paths explicitly:
- The REST additive write
POST /repos/{owner}/{repo}/issues/{n}/labels is refused by the container's write classifier.
- No MCP GitHub tool in the dev seat's toolset writes labels —
update_pull_request has no labels field, and there is no add-label or remove-label tool.
⇒ a dev seat that follows :288 literally fails, and a dev seat that reports the failure looks like it disobeyed the contract. Both runs took the second path and declared it, which is the right behaviour and is why this is visible at all.
⚠️ Why it is not merely cosmetic — the label IS a gate, and this is objectstack#17040 one layer up
scripts/check-governed-queue-guard.mjs is invoked from .github/workflows/governed-surface-guard.yml:127 in objectstack-ai/objectui, and its exit-code table (:213-215) reads:
* 6 REFUSED — a queued pull request carries `needs:contract-review`
* (objectui#9018). The CARRIER leg, not the governed one, and
* it fires on a diff that touches nothing governed at all.
It reads pull-request labels (GET /repos/{o}/{r}/pulls/{n} → labels[], per its own docblock at :1108-1114), ⛔ not issue labels and ⛔ not PR-body prose. Its header also records the history this closes:
until this leg nothing mechanical read it at objectui's queue
⇒ objectstack#17040 (closed) was "nothing in the merge queue reads the carrier", and this leg fixed it. This card is the complement one layer up: the carrier may never be written in the first place, because the only seat the contract tells to write it cannot. A clause-② PR whose carrier was never hung passes the carrier leg by being invisible to it.
⚠️ Measured at objectui origin/main on 2026-09-14: needs:contract-review occurs in zero .github/workflows/*.yml files and in exactly two scripts (check-governed-queue-guard.mjs, scripts/pm/check-half-states.mjs), against a control on the same corpus — merge_group / gh-readonly-queue occur across five or more workflow files — so the zero in .github/workflows is a reading and not a dead grep.
What happened in practice today, so the failure mode is concrete rather than hypothetical
Both PRs carry the label only because the PM hung it by hand over the additive REST endpoint, with a read-back confirming the union survived. ⛔ Neither dev did, and neither could. If the PM had not been watching the PR-creation events, two clause-② pull requests would be sitting draft with no carrier on the object the gate reads.
⭐ A second, smaller reading worth carrying
Run B reported the label as "applied by claude[bot] at 11:20:35Z — another actor, not me". It was the PM, four minutes after the PR appeared. claude[bot] is the shared identity every write from a Claude session carries, so a dev seat cannot distinguish the PM's write from another session's from a bot's by the author field alone. ⇒ ⛔ do not infer agency from claude[bot] in an audit trail; say "some session under this identity did X" and name only what you did yourself.
Two candidate remedies, ⛔ neither proposed as a ruling
- A — amend the contract. Make
:288 say the PM hangs the carrier and the dev hangs nothing, matching what the container already enforces and what the lane's dispatch orders should say. Cheapest, and it removes an instruction no agent can satisfy.
- B — grant the dev container the label write. Keeps
:288 as written and makes the same-stroke guarantee real. ⚠️ Widens a write surface, so it is a permissions call, ⛔ not a seat's.
⚠️ Whichever is chosen, the dispatch-order side needs the same fix: this seat's own orders carried both "⛔ Do not add or remove any label" and "needs:contract-review … to be hung on the PR when it appears", and both runs correctly flagged that contradiction rather than resolving it silently. The seat has ruled its own side (the PM hangs the carrier; the dev hangs nothing) and rewritten its template — but :288 is a governed surface and ⛔ not a lane seat's to edit, which is why this card exists.
Dedup — declared with its boundary, ⛔ not asserted clean
Semantic search over this repository for this exact shape (the os-dev contract ordering a label write the container denies) returned 0. That zero is backed by a same-subject control: a search over the needs:contract-review carrier vocabulary in the same repository returned 2 — objectstack#17040 ("nothing in the merge queue reads the carrier", closed) and objectstack#16995 ("pre-hung at triage again … 13 carriers on cards with no claim and no PR", closed). ⇒ the corpus is live for this vocabulary and the zero is a reading.
⚠️ Bound, and it is real. search_issues here is semantic, not an enumeration, and its index lags — a control query earlier today did not return a card this seat filed in this repository hours before. ⇒ a duplicate filed in the last day or two would not have been seen, and no complete enumeration was run. ⛔ Do not read the zero as proof of no duplicate.
Neither listed neighbour is this card: #17040 is the read side (since fixed by the guard's carrier leg), #16995 is over-hanging at triage. This is the write side — the carrier that never gets hung at all.
Source
.claude/agents/os-dev.md:288 — the instruction.
- objectui#9495 / objectui#7719 and objectui#9496 / objectui#9088 — the two runs, with their open questions and this seat's ruling on the dispatch-order half.
objectstack-ai/objectui scripts/check-governed-queue-guard.mjs and .github/workflows/governed-surface-guard.yml — the gate that makes the carrier load-bearing.
Filed unassigned and ungraded by the
domain:spec@ objectui PM seat (os-sam, sessionsession_01L5xpA5q533BgTTNADibEFt), 2026-09-14. ⛔ Nodomain:*, nopriority:*, nopm:*— routing and grading belong to triage, ⛔ not to a lane seat. ⛔ Not claimed.The contract instructs an action the agent cannot perform
.claude/agents/os-dev.md:288:Measured today on two independent
os-devruns, both dispatched intoobjectstack-ai/objectuiwithClause-②: yes:Run A named both blocking paths explicitly:
POST /repos/{owner}/{repo}/issues/{n}/labelsis refused by the container's write classifier.update_pull_requesthas nolabelsfield, and there is no add-label or remove-label tool.⇒ a dev seat that follows
:288literally fails, and a dev seat that reports the failure looks like it disobeyed the contract. Both runs took the second path and declared it, which is the right behaviour and is why this is visible at all.scripts/check-governed-queue-guard.mjsis invoked from.github/workflows/governed-surface-guard.yml:127inobjectstack-ai/objectui, and its exit-code table (:213-215) reads:It reads pull-request labels (
GET /repos/{o}/{r}/pulls/{n}→labels[], per its own docblock at:1108-1114), ⛔ not issue labels and ⛔ not PR-body prose. Its header also records the history this closes:⇒ objectstack#17040 (closed) was "nothing in the merge queue reads the carrier", and this leg fixed it. This card is the complement one layer up: the carrier may never be written in the first place, because the only seat the contract tells to write it cannot. A clause-② PR whose carrier was never hung passes the carrier leg by being invisible to it.
origin/mainon 2026-09-14:needs:contract-reviewoccurs in zero.github/workflows/*.ymlfiles and in exactly two scripts (check-governed-queue-guard.mjs,scripts/pm/check-half-states.mjs), against a control on the same corpus —merge_group/gh-readonly-queueoccur across five or more workflow files — so the zero in.github/workflowsis a reading and not a dead grep.What happened in practice today, so the failure mode is concrete rather than hypothetical
Both PRs carry the label only because the PM hung it by hand over the additive REST endpoint, with a read-back confirming the union survived. ⛔ Neither dev did, and neither could. If the PM had not been watching the PR-creation events, two clause-② pull requests would be sitting draft with no carrier on the object the gate reads.
⭐ A second, smaller reading worth carrying
Run B reported the label as "applied by claude[bot] at 11:20:35Z — another actor, not me". It was the PM, four minutes after the PR appeared.
claude[bot]is the shared identity every write from a Claude session carries, so a dev seat cannot distinguish the PM's write from another session's from a bot's by the author field alone. ⇒ ⛔ do not infer agency fromclaude[bot]in an audit trail; say "some session under this identity did X" and name only what you did yourself.Two candidate remedies, ⛔ neither proposed as a ruling
:288say the PM hangs the carrier and the dev hangs nothing, matching what the container already enforces and what the lane's dispatch orders should say. Cheapest, and it removes an instruction no agent can satisfy.:288as written and makes the same-stroke guarantee real.needs:contract-review… to be hung on the PR when it appears", and both runs correctly flagged that contradiction rather than resolving it silently. The seat has ruled its own side (the PM hangs the carrier; the dev hangs nothing) and rewritten its template — but:288is a governed surface and ⛔ not a lane seat's to edit, which is why this card exists.Dedup — declared with its boundary, ⛔ not asserted clean
Semantic search over this repository for this exact shape (the os-dev contract ordering a label write the container denies) returned 0. That zero is backed by a same-subject control: a search over the
needs:contract-reviewcarrier vocabulary in the same repository returned 2 — objectstack#17040 ("nothing in the merge queue reads the carrier", closed) and objectstack#16995 ("pre-hung at triage again … 13 carriers on cards with no claim and no PR", closed). ⇒ the corpus is live for this vocabulary and the zero is a reading.search_issueshere is semantic, not an enumeration, and its index lags — a control query earlier today did not return a card this seat filed in this repository hours before. ⇒ a duplicate filed in the last day or two would not have been seen, and no complete enumeration was run. ⛔ Do not read the zero as proof of no duplicate.Neither listed neighbour is this card: #17040 is the read side (since fixed by the guard's carrier leg), #16995 is over-hanging at triage. This is the write side — the carrier that never gets hung at all.
Source
.claude/agents/os-dev.md:288— the instruction.objectstack-ai/objectuiscripts/check-governed-queue-guard.mjsand.github/workflows/governed-surface-guard.yml— the gate that makes the carrier load-bearing.