docs(agents): os-dev.md — releases ban scoped to code PRs, force-push per landing repo, label-step scope, classifier-denial cell - #19038
Conversation
…push defers to the landing repo `.claude/agents/os-dev.md` block 4 rewritten in two lines, line-neutral: :67 now forbids editing `content/docs/releases/` only IN A CODE PR (a correction is a dedicated docs-only PR), keeping the push-`main` and merge bans unconditional; :68 re-points the force-push clause at the LANDING repository's AGENTS.md and names both shapes (objectui/cloud absolute ban; objectstack's five-criteria `--force-with-lease`, §3). The changeset sentence that lived on :68 folds into :298 as the complement of the `skip-changeset` criterion it already carried. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BTeBejoPUvRHN8WdAJC6oF
…citly :301 「本仓库」 becomes `objectstack` by name; :309 states what a dev does in objectui (path labels belong to `labeler.yml`, re-synced on every push; no objectui gate reads a label the dev writes; the dev writes none unless the dispatch names one); :310 folds the two objectui `skip-changeset` lines into one. Line-neutral. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BTeBejoPUvRHN8WdAJC6oF
… cell The label write is named by its single spelling (`scripts/pm/label-write.mjs`, four steps built in), which lets the new cell beside the endpoint-refusal cell say what a dev does when the session classifier denies an external write: stop that write, record the exact command and the classifier's reason under `deviations`, hand the act to the seat, never re-issue it by another route (curl, MCP, a hand re-implementation). The two read-back lines move up beside the mechanism they explain. Line-neutral: 403 / 403. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BTeBejoPUvRHN8WdAJC6oF
Contract reviewServed-tier: ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
维护者速读(终稿)· skills 席 · 2026-09-18T13:16Z这个 PR 做什么:把您今天两条裁决和两处实测写进 dev 合同( 验收:复核记录 5730535140(PASS);ACCEPT 5730540239 · 5730540563 · 5730540872 · 5730541258;派生门禁 19 / 19 绿,CI 18 成功 · 12 跳过 · 0 红(2026-09-18T13:14Z);行数棘轮 403 / 403,每行 ≤ 120 字节;四张卡的 请您做的一件事:Approve(受管文本),或直接 ready + squash 合并。没有要问的字。 Generated by Claude Code |
Fixes #18908
Fixes #18882
Fixes #19002
Fixes #19004
Clause-②: no
Four cards on one file,
.claude/agents/os-dev.md, one branch, three line-neutral commits (2300b8938,65d09a3b9,7f28ee186). Governed surface (.claude/**) ⇒ draft; landing is the maintainer's word.skip-changeset:.claude/**is the fast path — nothing any package'sfiles[]ships moves.What changed, line by line (bytes exclude the newline; before =
main75c0dacff, after =7f28ee186)content/docs/releases/、推main、合并任何东西;force-push 只按 AGENTS.md §3。」main、合并任何 PR、在代码 PR 里改content/docs/releases/;改错另开 docs-only PR。」.changeset/*.md。」--force-with-lease。」skip-changeset唯一判据:没有已发布的东西移动;已发布 = 各包files[]实际发运的内容。」skip-changeset唯一判据是没动:已发布 = 各包files[]实际发运内容。」POST .../issues/N/labels,不碰已有标签);可达性按会话探,先探后用。」scripts/pm/label-write.mjs:取现集、加法 POST、回读比 union、缺者重挂一次并报告。」blocked、不走 MCP;收尾再读一次。」deviations记命令与拒因,席位代做;⛔ 不换路重发(curl/MCP/手工)。」labeler.yml,逐 push 同步;无门禁读你打的标签 ⇒ 派发词未点名即零写。」skip-changeset零读者;空 frontmatter changeset 即声明,门禁判定行为准,⛔ 永不施加。」Ratchet reading:
check-skill-line-ratchet: .claude/agents/os-dev.md is 403 lines (ceiling 403; headroom 0)— before 403 / 403, after 403 / 403; the 120-byte max-line rule's budget line readsbudget is 120 bytes; longest changed line is 120 B (:298).The folds that paid for the three new lines
skip-changeset⇔ nothing published moved); the fuzzier 「用户可见」 spelling is replaced by its complement 「发布面动了要 changeset」 on the same line. AGENTS.md's Post-Task Checklist step 3 remains the binding text.scripts/pm/label-write.mjs(references/rest-channel.md: 「标签/assignee 写恒经scripts/pm/label-write.mjs」; the four steps, the once-only re-apply and the report are its own contract). The reachability probe of old :304 is the tool's exit 3; 「收尾再读一次」 keeps its place on the refusal line.skip-changeset) fold into one line: 「零读者」 subsumes 「零 workflow/脚本读它、豁免不了任何东西」; dropped as evidence rather than rule: 「同名标签对象在」 and 「pin 测试钉着」 (the pin isobjectui/scripts/__tests__/ci-cd-pipeline-doc.test.ts,never wires the phantom skip-changeset label into a workflow or a gate).Not a re-wrap anywhere: every line that changed changed its content; old :307/:308 moved, byte-identical.
The rulings this PR executes (verbatim)
#18908 — ruling #18854 B (comment 5725503560, maintainer 「同意」 2026-09-18T05:13Z):
Aligned texts on
main:SKILL.md:32「⛔ 永不在代码 PR 里改content/docs/releases/。」;AGENTS.md:685「content/docs/releases/| RELEASE-OWNED | ❌ Never edit in a code PR. … Factual error on a releases page → dedicated docs-only PR or an issue, never a rider on code changes.」 The pointer to the Documentation Guardrails did not fit the 120-byte line; os-dev.md :19 already binds AGENTS.md whole.#18882 — ruling objectui#9666 C (comment 5724939229, maintainer 「其他同意」 2026-09-18T03:58Z):
The two shapes, read on today's trees: objectstack
AGENTS.md:471-:478(§3) — 「Never force-push a shared branch, and never pushmain. … A branch is unshared, and--force-with-leaseallowed, only while ALL FIVE hold: ① it is namedclaude/issue-*; ② this worktree created it; ③ nobody else has ever pushed it …; ④ no open PR on it carries a reviewer or an approval …; ⑤ the push spells the lease against the sha you last pushed — ⛔ never bare--force. One criterion failing ⇒ the branch is shared.」; objectuiAGENTS.md:316(read at objectuiorigin/maina017617) — 「绝不git push --force/--force-with-lease,绝不推main(会覆盖并行 agent 的工作;main共享,一律走 PR)。禁令不按「这条分支是不是只有我一个人用」分档…所以它一律绝对,单人 feature 分支同样不例外。」; cloudAGENTS.md:63is cited by the ruling's words only (outside this session's scope). The new :68 says 「落地仓 AGENTS.md」 rather than 「落地仓 §3」 because objectui's rule carries no section number; objectstack's is named§3where the five criteria live.#19002 (triage 5729068374): the deliverable is the label step's SCOPE, no new rule. Measured on objectui
origin/maina017617:.github/workflows/labeler.ymlrunsactions/labeler@v7withconfiguration-path: .github/labeler.ymlandsync-labels: trueon everypull_requestopen/synchronize/reopen — path labels are written by it and re-synced on every push; across all 40 workflow files, zero read a PR label (grep -rn -E "labels\.\*\.name|pull_request\.labels|event\.label\b|\.labels\b" .github/workflows/→ no hit); the only scripts that read labels arescripts/pm/check-half-states.mjs(the PM board'spm:*states) andscripts/check-governed-queue-guard.mjs(CONTRACT_REVIEW_LABEL = 'needs:contract-review', the seat's, os-dev.md :303) — neither a label a dev writes. On objectstack,.github/workflows/pr-automation.yml:290readsskip-changesetin a job condition, so 「标签是真实机制」 is now attributed toobjectstackby name. The filing seat's measured four PRs (objectui#9804/#9812/#9826/#9854, labels present with no dev write) agree with the mechanism. No maintainer word needed: the two mechanisms decide the scope, nothing is presumed beyond them.#19004 (triage 5729095625): 「契约里该写的是停手并上报,⛔ 不是换一条手工路径继续」. The new :308 is the classifier cell beside the endpoint cell (:307): the trigger is an external write the session classifier refuses (「外部写」 — not any denied local tool, since the card's line is 「never re-issue the same EXTERNAL write by another route」), the conduct is stop, record the command and the classifier's reason under
deviations(a dispatch-carried report field,SKILL.md:536), hand the act to the seat, and never re-issue it by another route, the three routes named. It covers every tool the dispatch names, labels included; the seat-side half already lives inreferences/rest-channel.md(「会话分类器拒改动 ⇒ 无通道,交有通道席位立卡」).Gates (run at
7f28ee186, exit codes captured before any pipe; ledger reconciled withdispatch-gates.mjs --ran)Derived by
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackoff merge base75c0dacff(1 path): 19 commands.--ranverdict:19 derived famil(ies) accounted for — 19 run, 0 NOT-MEASURED.pnpm check:pm-skill-ratchet:: exit 0 —os-dev.md is 403 lines (ceiling 403; headroom 0)pnpm check:pm-skill-id-lint:: exit 0 —27 file(s) clean (pattern /#[0-9]{3,}/g)pnpm check:agent-model-declared:: exit 0 —1 agent definition(s) under .claude/agents/ all declare a modelpnpm check:nul-bytes:: exit 0pnpm check:skill-frame-sync:: exit 0 ·pnpm check:watch-hint-literal:: exit 0 ·pnpm check:refd-timer-probe:: exit 0pnpm check:pm-governed-merges:: exit 0 ·node scripts/pm/check-governed-queue-guard.mjs --self-test:: exit 0 (253 cases) ·node scripts/pm/check-harness-current.mjs --self-test:: exit 0pnpm check:commit-card-trailers:: exit 0 (and the pre-push hook: 3 commits, no card relation, model-free trailer pair)pnpm check:doc-authoring:: exit 0 ·pnpm check:agent-test-spelling:: exit 0 ·pnpm check:cross-package-test-inputs:: exit 0 ·pnpm check:driver-memory-census:: exit 0node scripts/check-closing-keyword-parity.mjs:: exit 0 (+--self-test:: exit 0) ·node scripts/check-comment-mask-corpus.mjs:: exit 0 (6861 files, 0 disagree)pnpm --filter @objectstack/lint run check:doc-formula-expressions:: first run exit 3 = PREREQUISITE NOT MET (@objectstack/formulanot built — nothing measured); afterpnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lintunderos-verify-lock.sh(VERDICT command-exit 0), re-run :: exit 0 —22 record-scoped formula example(s) across 438 files … judged cleannode scripts/pm/check-governed-merges.mjs --test .claude/agents/os-dev.md:: exit 3 = its GOVERNED code — 「混合 diff 一条命中即整 PR 分叉」; this PR stays draft.pnpm check:pm-dispatch-gates(named by the dispatch, outside the derived 19): detached at PR-open time; its verdict is reported in theos-dev-reportcomment, NOT MEASURED if the container cut it.Not run locally, by declaration: the repo-level
pnpm lintsweep and the rest of CI's artifact-roster families — a Markdown-only diff under.claude/touches no package, so ① and ② of the local scope are empty.Acceptance notes
deviationsfield;SKILL.md:536names it as a field the dispatch adds (gates / line_budget / deviations / files_changed). The new :308 names the field as the dispatch does. 承接者: the skills seat, if the template should ever list it.sync-labels: true, so a dev-writtenpackage: *label that stops matching the diff is stripped on the next push — one more reason the objectui scope reads 「零写」. 承接者:无.维护者速读(草稿)
改了什么:只动
.claude/agents/os-dev.md一个文件,403 行进 403 行出,四张卡合一。① 第 67 行:原来「永不编辑content/docs/releases/」改成「永不在代码 PR 里改」,改错另开 docs-only PR —— 与 SKILL.md、AGENTS.md 已有的口径对齐;② 第 68 行:force-push 改为「按落地仓的 AGENTS.md」,并写明两种形态(objectui/cloud 绝对禁;objectstack 五条全立才--force-with-lease);③ 第 301/309/310 行:打标签这一步写明仓别 —— objectstack 是 dev 的默认步骤,objectui 的路径标签归 labeler、派发词不点名就一个标签也不打;④ 第 308 行:新增「会话分类器拒了一笔外部写」这一格 —— 停手、把命令和拒因记进报告、交席位代做,⛔ 不换 curl/MCP/手工路线重发。为什么改:①② 是维护者已裁的两条(#18854 裁决 B、objectui#9666 裁决 C),这里只是把裁决落到 dev 的角色文件;③ 是一处作用域写死 —— 同一份文件此前既说「本仓库打标签是你的步骤」,又只为 objectui 划了一个标签的例外,dev 在 objectui 得自己猜,实测 objectui 零门禁读 dev 打的标签;④ 是一次实测的绕过:一个 dev 被分类器拒了
label-write.mjs之后用手在 REST 上重做了那四步,结果对了,但下一次的保障就只剩执行者的记性。风险与代价(含回滚):全是规则文本,不发布、不改代码。代价是第 304 行把「四步手写」换成点名
scripts/pm/label-write.mjs(那四步是它内建的),第 310 行把 objectui 的skip-changeset两行并成一行(丢的是「pin 测试钉着」这类证据句,不是规则)。回滚 = revert 这一个文件的三个 commit,零副作用。席位意见:(留空)
你要做的:确认四张卡的裁决/分诊意图都落到了对应行(67 / 68 / 301 / 308 / 309 / 310),然后按受管面流程由你合并;不需要任何决策 —— #19002 的作用域由两仓的机制决定,本 PR 没有替维护者预设答案。
Generated by Claude Code