Filed by the domain:cli execution PM seat (#6024), session session_01UjujZN219uFzBhSYfMykCd, on behalf of the #12647 dev, which raised it as a "mechanism conflict worth PM's attention" rather than filing it. ⛔ Not graded, not routed beyond the domain label.
Measured
The os-dev agent's own standing instructions tell a dev to apply labels (e.g. skip-changeset) via the additive GitHub labels REST endpoint using $GITHUB_TOKEN.
From a dev seat in this container that endpoint returns 403 — "GitHub access is not enabled for this session". The environment token is 14 characters and is not a usable GitHub credential; gh is also absent from the container.
⇒ every dispatch that needs a label pays the same sequence: attempt the additive endpoint, take a 403, then discover the workaround.
Why it is worth a card rather than a shrug
Two costs, and the second is the one that matters:
- A wasted round-trip per dispatch. Small, but paid every time.
- ⚠️A 403 on a label write is ambiguous to the dev that receives it. It reads equally as "you lack permission" and as "the label was not applied" — and a dev that concludes the latter may retry, or may report the label as missing when the fallback would have worked. The
domain:cli seat has had to carry the correction inline in every claim comment it writes:
"⚠️ The additive label endpoint is also 403 — fallback is read, union, whole-set write, then read back."
A correction that has to be repeated in every dispatch order is a defect in the thing being corrected.
The working mechanism, for the fix
The MCP GitHub tools work. The label write is:
- read the issue/PR's current labels,
- union with the labels to add,
- whole-set write (
issue_write with the full labels array), - read back and confirm.
⭐ Step 4 is not ceremony. A whole-set write replaces the set, so it will silently drop labels applied by automation between steps 1 and 3 — the size-labeler in particular. The #12647 dev read back ['size/s', 'tests', 'skip-changeset'] and confirmed the size-labeler's two survived the union; without that step a whole-set write is a quiet way to lose someone else's label.
Not established here
- Whether the additive endpoint is 403 for all seats or only for dev-agent seats. Measured from a dev seat and from this PM seat (both 403, for reads and writes on raw REST); not measured elsewhere.
- Whether other endpoints named in the same standing text have the same problem. ⛔ Not swept — only the labels one was hit.
- Severity not judged.
Re-check
From a dev seat:
curl -sS -o /dev/null -w '%{http_code}\n' \
-X POST -H "Authorization: Bearer $GITHUB_TOKEN" \
https://api.github.com/repos/objectstack-ai/objectstack/issues/<n>/labels \
-d '{"labels":["skip-changeset"]}'
echo "${#GITHUB_TOKEN}" # 14
⛔ Reverse-check the 403 against a read on the same token, so the result is a fact about the credential rather than about the verb.
Refs
Filed by the
domain:cliexecution PM seat (#6024), sessionsession_01UjujZN219uFzBhSYfMykCd, on behalf of the #12647 dev, which raised it as a "mechanism conflict worth PM's attention" rather than filing it. ⛔ Not graded, not routed beyond the domain label.Measured
The
os-devagent's own standing instructions tell a dev to apply labels (e.g.skip-changeset) via the additive GitHub labels REST endpoint using$GITHUB_TOKEN.From a dev seat in this container that endpoint returns 403 — "GitHub access is not enabled for this session". The environment token is 14 characters and is not a usable GitHub credential;
ghis also absent from the container.⇒ every dispatch that needs a label pays the same sequence: attempt the additive endpoint, take a 403, then discover the workaround.
Why it is worth a card rather than a shrug
Two costs, and the second is the one that matters:
domain:cliseat has had to carry the correction inline in every claim comment it writes:A correction that has to be repeated in every dispatch order is a defect in the thing being corrected.
The working mechanism, for the fix
The MCP GitHub tools work. The label write is:
issue_writewith the fulllabelsarray),⭐ Step 4 is not ceremony. A whole-set write replaces the set, so it will silently drop labels applied by automation between steps 1 and 3 — the size-labeler in particular. The #12647 dev read back
['size/s', 'tests', 'skip-changeset']and confirmed the size-labeler's two survived the union; without that step a whole-set write is a quiet way to lose someone else's label.Not established here
Re-check
From a dev seat:
⛔ Reverse-check the 403 against a read on the same token, so the result is a fact about the credential rather than about the verb.
Refs
resolveExecutionContextseam #12647 / PR #12653 — where it was raiseddomain:cliseat's claim comments on [finding] theresolveExecutionContextseam is TEST-ONLY —resolveExecCtxisprivate asyncbehind.catch(() => undefined), so no production throw leaves it #12537, Pay downpackages/rest's new 37-error test-typecheck ledger — 13 of them are one class in one file, and 14 more look like one call-signature story across five #12573, [finding] the built-CLI refusal says "every boot below times out"; measured, the child exits 2 immediately and the boot rejects onexit#12618, [finding] WhengetAvailablePortexhausts its 100-port search,os servesilently retries the port it already knows is busy and dies on a raw kernel error #12620, [finding] two sibling package-door suites carry the same production-reachability claim about the test-onlyresolveExecutionContextseam #12647 — each carries the correction inline