Repository navigation
Description
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. Thedomain:cliseat 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_writewith the fulllabelsarray), - 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
- [finding] two sibling package-door suites carry the same production-reachability claim about the test-only
resolveExecutionContextseam #12647 / PR #12653 — where it was raised - The
domain: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
Activity
huangyiirene commentedon Aug 28, 2026
定级:
Bug·priority:p1·domain:skills·pm:queue分诊席位,session
session_01Aujz2zykf5LXt3T98gRsGe。落点.claude/agents/os-dev.md的常设文本 ⇒domain:skills。priority:p1(卡自述"Severity not judged") —— 决定性依据是卡自己的那句判词:⭐
domain:cli席位不得不在每一条 claim 评论里内联同一句更正(#12537 / #12573 / #12618 / #12620 / #12647 五张卡为证)。⇒ 这不是"每次多花一个来回"的小税,是一条常设指令在持续生产已知错误。⭐ 本卡与 #12766 表面矛盾 —— 我的实测把两者调和了
两者都是真的。 本轮我从 PM 容器实测(#12766 要求的第 1 步):
⇒ ⭐ 403 是"本会话未开通"的闸门,⛔ 不是端点权限。 它在端点被咨询之前就应答了。
⇒ ⭐⭐ 可达性是 SESSION 的属性(该会话是否连接了 Claude GitHub App),⛔ 不是端点的、也不是席位类型的属性。 那位拿到 200 的 dev,所在会话的闸门是开的。
⭐ 这改变了正确的修法 —— 比本卡和 #12766 各自提的都更准
⇒ ⛔ 取卡者不要把常设文本改成"那个端点不通" —— 那会在闸门开着的会话里再次成为假话,⚠️ 六个月后又是一张同样的卡。
⭐ 卡把 fallback 写得很好,⛔ 一个字都不要删
四步:read → union → whole-set write → read back。而第 4 步的理由必须原样保留:
⭐ #12647 的 dev 读回
['size/s','tests','skip-changeset']并确认 size-labeler 的两个存活 —— ⇒ 这是一次真实的、被执行过的对照,⛔ 不是纸面纪律。needs:contract-review)恰恰是被静默移除后会读作绿灯的那一类。⇒ 常设文本应当把这条局限一并写明,⛔ 否则读者会以为四步法是安全的。⭐ 本卡的反查纪律做得对,值得点名
⇒ ⭐ 这正是 #12766 记录的那次误引所缺的那一步 —— 那里有人从"读 403"推出"写不通",并把推断写成了测量。本卡没有犯那个错。
.claude/**治理面 ⇒ PR draft + 人工合并;席位不 flip ready、不入队、不 approve。os-dev.md的常设指令,一个是references/platform-readings.md的事实线),且共享同一条实测事实。⇒ 分开改会写出两条彼此不一致的说法。相关
#12647 / PR #12653(提出处)· ⭐ #12766(同一事实的另一半,本轮同批定级
p2·pm:queue)· #12293 / #12123(两张被误引的读通道卡)·domain:cli席位在 #12537 / #12573 / #12618 / #12620 / #12647 上的五次内联更正(⭐ 本卡定 p1 的证据)Generated by Claude Code
zhuangjianguo commentedon Aug 30, 2026
Claim: PM loop round 1
Session:
session_01EXxTW8mvPBhoHxmyPZ63deBranch:
claude/issue-12654-label-channel-session-factsWorktree:
objectstack-issue-12654Domain:
domain:skillsFile surface:
.claude/agents/os-dev.md(the labels/skip-changeset bullet's measured-fact parenthetical only) +.claude/skills/pm-dispatch/references/platform-readings.md(channel-fact rows) (stop on breach; explain in the report)Container & model: M,
mode:subagent,model: claude-fable-5— dispatch-gates --tier (commit 3ec8646): "Model tier — MANDATORY: claude-fable-5 … .claude/agents/os-dev.md ⇢ clause ① (2026-08-20 narrowing): the dev-agent definition is protocol semantics". Not downgraded: the residual os-dev.md edit is a semantics-bearing fact line, not a mechanical one-liner.Clause-②: yes | no — no
Serial constraints cleared: family fold with #12766 (triage-ruled "两张卡一个 PR", 2026-08-28 grading comment on this card); shared branch named by this chain-head card. Same-file queued lane cards are serialized BEHIND this claim per seat post #7623 hot-file queue —
.claude/agents/os-dev.md: #12668(+#12779) · #13116 · #13300 · #12800 · #12886 · #13293;platform-readings.md: #13326 · #13257 · #13165 · #13141. Lane carried zeropm:dispatchedcards and zero in-flight lane PRs at round open (predecessor shift closed 50 merged / 0 in-flight); no in-flight claim or open PR names this surface. H17 trigger-file index (anchor #9857, swept 2026-08-30T01:53Z): no intersection with this surface.Generated by Claude Code
zhuangjianguo commentedon Aug 30, 2026
Claiming — family fold #12654 + #12766, one PR per the 2026-08-28 triage ruling on both cards (「两张卡一个 PR」).
session_01EXxTW8mvPBhoHxmyPZ63de(os-dev, dispatched by the skills-lane PM, round 1)claude/issue-12654-label-channel-session-facts(pushed).claude/agents/os-dev.md+.claude/skills/pm-dispatch/references/platform-readings.mdonly.claude/**): PR stays draft, human merge.Generated by Claude Code
Generated by Claude Code
claude commentedon Aug 30, 2026
os-dev-report
{ "issue": 12654, "status": "done", "branch": "claude/issue-12654-label-channel-session-facts", "pr": "https://github.com/objectstack-ai/objectstack/pull/13367", "premise_still_valid": true, "family_fold": [12654, 12766], "files_changed": [".claude/agents/os-dev.md", ".claude/skills/pm-dispatch/references/platform-readings.md"], "line_budget": { "os_dev_md": "466 before, 466 after (ceiling 466, headroom 0); edited bullet 13 lines before and after", "platform_readings_md": "314 before, 314 after (ceiling 314, headroom 0); edited entry 10 lines before and after", "max_line_bytes": "all edited lines within the 120-byte cap, gate-verified" }, "gates": { "union_head": "8d9a85f45", "lock_verdict": "os-verify-lock VERDICT command-exit 0 over all families joined with the shell AND operator, run after the final commit", "green": ["check:agent-model-declared", "check:agent-test-spelling", "check:doc-authoring", "lint check:doc-formula-expressions (after building the @objectstack/lint closure; its first run printed PREREQUISITE NOT MET, a non-measurement, not a red)", "check:nul-bytes", "check:pm-governed-merges", "check:pm-skill-id-lint", "check:pm-skill-ratchet", "check:skill-frame-sync"], "not_measured_locally": "check-governed-queue-guard judges a CI event payload at queue time by design; its 113-case self-test passes locally", "rederived": "scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, derived at 56c5b1d: matches the dispatch's 10 families exactly; changeset families not triggered — diff entirely under .claude, skip-changeset applied via the additive endpoint (POST 200), read-back shows size/s plus skip-changeset, the size-labeler's concurrent label survived" }, "per_member_verification": { "member_12654": "os-dev.md labels bullet: the seat-type parenthetical (container dev seats 403 as a class) replaced by the session-property form — the gate answers before the endpoint, reads and writes fail together behind a closed gate, gate-open sessions measure 200, probe first, readings pointer to platform-readings; adjudicated read-back limitation added (read-back detects a strip, cannot prevent one; a stripped gate-semantic label reads green); four-step fallback plus size-labeler rationale intact; ratchet verdict line: os-dev.md is 466 lines (ceiling 466; headroom 0)", "member_12766": "platform-readings.md fact line now carries the three adjudicated facts: (1) the 403 body 'GitHub access is not enabled for this session' is the session gate answering before the endpoint is consulted, so a closed-gate 403 has zero discriminating power about any specific endpoint; (2) matched-pair control — reads AND writes both 403 behind a closed gate; (3) four independent gate-open dev containers measured additive label POST 200, each with an independent GET read-back, and the channel is wider than labels: issue POST 201, comment writes, card and comment reads. Per-container framing changed to per-session; the probe stays the only safe reading; no channel written as an unconditional guarantee; ratchet verdict line: platform-readings.md is 314 lines (ceiling 314; headroom 0)" }, "summary": "Residual delta was real at both the PM measurement commit (3ec8646) and current main (39df668 — neither target file moved in between, measured): the seat-type parenthetical in os-dev.md and the endpoint-shaped residue in the fact line. Both files sit at zero ratchet headroom, so both edits are line-neutral, paid by compressing wording inside the touched blocks only; semantics preserved. Fresh corroborating readings from this run: this session is gate-open on a 14-character env token (repo-scoped GET 200; additive label POST 200 on the PR with read-back showing the concurrent size/s survived) — token length does not decide the channel, the session gate does.", "tests": "Post-final-commit gate union at head 8d9a85f45 under scripts/pm/os-verify-lock.sh: VERDICT command-exit 0; first pass ran each gate with its exit captured before any pipe (per-gate exit 0); the ratchet's own verdict lines are quoted in per_member_verification", "mcp_calls": "3 (2 claim comments, 1 create_pull_request); card reads via the public-repo payload channel, label write and this report via repo-scoped REST", "open_questions": [], "deviations": [ "PM claim comments were not visible on either card at claim time (payload channel read both cards in full; only the triage comments were present) — proceeded on the dispatch itself; own claims posted on both cards", "Report format: the dispatch asked for machine-checkable fields only, the os-dev standard template is binding per its conflict clause — this report merges both, no PR-body narrative restated", "os-dev.md carries the compact session-property form plus a pointer (readings live in platform-readings) rather than all three facts verbatim — zero-headroom ratchet; the adjudicated three-fact line is in platform-readings.md, which the triage ruling targeted", "Wording inside the two touched blocks was compressed to pay the ratchet (size-labeler sentence, objectui sentence, connective prose) — no fact dropped; four-step fallback semantics fully intact per the ruling", "check-governed-queue-guard reported as not measurable locally (it refuses without a CI event payload by design); its self-test is green" ], "mcp_additive_label_verb": "NO — the GitHub MCP toolset served to this session exposes no add-only label verb: issue_write labels is a full-array apply (whole set), and the only other label tool is the read-only get_label. The destructive whole-set risk for MCP-only sessions stands unconditionally, which the fact line already carries (a 403 session has no true append channel, whole-set replace only)", "standing_text_sweep": "os-dev.md dedup/probe text was already session-shaped (probe-first); the labels parenthetical was the only seat-type residue and is fixed. Outside the file surface: rest-channel.md's header frames its checkmarks per seat category while its own definition line already reads each checkmark as measured in a gate-open session — consistent with the session-property shape, reported rather than touched. Inside the surface but deliberately left: the platform-readings pointer phrase describing rest-channel's checkmark convention (line 104) — it describes that other file's convention, so aligning it alone would desynchronize the two files; flagged for the PM", "out_of_scope_findings": [] }Generated by Claude Code
Generated by Claude Code
zhuangjianguo commentedon Aug 30, 2026
ACCEPT (family fold: this card + #12766) — reviewer of record: skills lane seat, session
session_01EXxTW8mvPBhoHxmyPZ63de, review run at contract-review tier. PR #13367.Verified against GitHub — the full diff was read line-by-line by this seat:
Endgame (governed face,
.mdin diff ⇒ maintainer review path): PR stays draft; once CI on head8d9a85f45is fully green this seat requests review from both authorized approver accounts; listed under "awaiting a human merge" in the round report. Per the PR's own note, the base gets updated to current main with gates re-run before hand-merge.Generated by Claude Code