docs(pm): the charter states how to test whether a release is staged — by head branch, never by title - #17850
Conversation
…nch, never by title The triage charter demanded a lit control for every zero reading but named no instrument for "is a release staged", so each seat invented one at the point of use. The criterion now lives next to the card re-check hard lines: the head branch `changeset-release/main`, a copyable query, a lit control, the explicit refusal of the PR title as a test (the two repos' titles differ and are action-configured), and the sharper reading — whether this card's changeset is already folded into that head's `CHANGELOG.md`. Paid inside the same file at its ceiling: two rationale tails and one three-zone restatement whose single source is SKILL.md and the dev-agent definition. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MCLBsUgfykL74aU716rzVK
维护者速读改了什么 — 派发细则( 为什么改 — objectui#9065 复核时一个席位现场发明了「找标题为 Version Packages 的 PR」这条查询,它在两仓任何时刻都恒返 0,渲染出的答案恰好是「窗口没关,慢慢来」。零配对照的纪律本来就在,缺的是仪器本身;#17026 是窗口关掉后错句永久留在 CHANGELOG 的实测先例。 风险与代价(含回滚) — 纯章程文本,不碰脚本、门禁、禁令(不跑发布、不催发布 PR 原样);删掉的五行在 PR 正文逐条列出,若想保留某行,正文给了三处可替换的付账点。回滚即 revert。 席位意见 — 接受(ACCEPT 5645955481,契约档复核)。一条后续由本席承担:SKILL.md 里加一行指向此条款的指针,搭下一张 SKILL.md 的 PR(PR #17837 落地后的 #17728)。 你要做的 — 受管面( Generated by Claude Code |
The triage charter already demanded a lit positive control for every zero reading, but it named no instrument for "is a release staged" — so a seat needing that judgement invented one at the point of use, and the invented query (the PR title
Version Packages) can never hit in either repo. The zero it returns renders as exactly the answer the asker wanted: the window is open, take your time. This PR writes the criterion into the charter, immediately before the card re-check hard lines that demanded the control: the head branchchangeset-release/mainis the test, with one copyable query and one lit control; the PR title is explicitly refused as a test, because the two repos' titles differ and are configured on the Changesets action; and the sharper reading — whether this card's own changeset is already folded into that head'sCHANGELOG.md— is what answers how far a statement is from permanent, which is the question worth asking. No prohibition changed, no ledger, no gate.Fixes #17830
Acceptance notes
Premises, re-verified on
origin/mainat758ac4097(all four hold)git grep -n -E -i "changeset-release|release window|发布窗口|上膛" origin/main -- .claude/skills/pm-dispatch/exits 1 with zero output.git grep -n "Version Packages" origin/main -- .claude/skills/pm-dispatch/returns exactly two lines,SKILL.md:34andSKILL.md:683, and both are prohibitions (never run a release / never chase the release PR), never a detection instrument. Control for the zero:git grep -l "分诊" origin/main -- .claude/skills/pm-dispatch/lists 15 files includingreferences/dispatch-runbook.md, so the instrument reads the corpus the zero was taken over.GET /repos/objectstack-ai/objectstack/pulls?state=open&head=objectstack-ai:changeset-release/mainreturns HTTP 200 with exactly one element: PR 17076, titlechore: version packages, headchangeset-release/main,state: open,draft: false, authorgithub-actions[bot], created 2026-09-09T06:17:15Z. One hit per repo, as the card says.references/landing-operations.md69 lines / ceiling 69,references/dispatch-runbook.md241 / 241,MAX_LINE_BYTES = 120.SKILL.md(812/812) was left untouched as instructed.SKILL.md+references/core-rules.md(PR 17837),references/decision-analysis.md(PR 17515) andreferences/platform-readings.md(PR 17803).references/dispatch-runbook.mdis free.Carrier chosen:
references/dispatch-runbook.md, section 「落卡与裁决记录细则」Both candidates were read in full first.
landing-operations.mddeclares its own scope in its second line — the operational detail for moving a PR from ACCEPT to MERGED — and the question this card is about arises much earlier than ACCEPT: it is a grading input, before a card is even dispatched.release-aftercare.md(a third candidate the ratchet map exposes, 50/50) declares itself as what is owed after a tagged release rolls, which is the other side of the same boundary.What a seat actually does when it asks 「这张卡会不会被下一次发布关掉窗口」 is take a reading and record it on the card as the justification for a
priorityor apm:blocked.dispatch-runbook.md's 「落卡与裁决记录细则」 is the one section in the charter that governs a reading recorded on a card, and it is where the two hard lines for a zero live: every grep carries a positive control, and a zero whose control did not light is recorded as "did not read", never as "does not exist". That is precisely the discipline the failing seat honoured in form while the instrument it pointed at did not exist. The criterion is therefore placed immediately before those hard lines, so the reach for 「零配对照」 lands on a real instrument instead of an invented one. Placing it anywhere else leaves that reach still pointing at nothing.The four lines were inserted before the 「卡上 re-check 命令两条硬线」 bullet rather than inside it: that bullet opens an ①/② enumeration which closes two lines later, and so does the 「记录锚在活得下来的对象上」 bullet after it, so those were the two spots an insertion would have split.
Every edited line, with its byte count (cap 120)
Added:
- 发布窗口判据:已上膛 = 开着的 head ...changeset-release/main... PR,...is:pr is:open head:changeset-release...。- 点亮对照 ...git ls-remote origin changeset-release/main... 必中;⛔ title 永不是判据。- 两仓 title 不同、由 action 配置:objectui ...chore: release packages...、objectstack ...chore: version packages...。- 上膛与否不足:真判据是本卡 changeset 已否折进该 head ...CHANGELOG.md...,即「离永久还有多远」。- 三分区各自的 dev 义务单源见 SKILL.md 与 os-dev 定义,派发词 ⛔ 不复述。(The backtick spans are written with ellipses in this table only, to keep the row inside the rendered width; the file carries them as ordinary inline code.)
Deleted: 115 B, 100 B, 64 B, 119 B, 73 B (listed under "how density was paid").
Line count: 241 before, 241 after — the file stays exactly at its ceiling, no raise. Bytes: 471 deleted against 545 added, so the file grows 74 bytes at a flat line count; that is inside the design the ratchet header states, since the 120-byte cap is what keeps a line a unit.
How the density was paid — deletions only, never a re-wrap
Five lines were removed and one pointer line added, funding four new lines at net zero. No two bullets were merged to buy a line: merging wrapped lines is not legal currency here, so every payment below is content that leaves the corpus with a live single source elsewhere.
级序理由:p0 是显式裁定,…(115 B, section 「车道取卡全序」) — a rationale tail for an order that is itself stated inSKILL.md:458–460(取卡全序:priority:p0 > pm:blocking > target: 板上项 > p1 > p2 > p3 > 无级;同级先 Bug 再卡龄, plus 「优先是排序不是豁免」). The rule stays; only the "why" goes, which is the class the ruling behind this file's own ceiling sends out of the corpus.理由两条:标签说不出是哪个问题;…(100 B, the same section as the addition) — a rationale tail for the rule on the line above it (裁决执行中新生的问题另立卡并回链已裁卡), which stands without it.SKILL.md:531already carries the zones with their obligations in the parenthetical (裁决(不可重裁)/ PM 机制假设(须实测,鼓励证伪)/ PM 建议的路线(可选,实测优先)),references/core-rules.md:114carries the PM-side half, and.claude/agents/os-dev.mdcarries the dev-side half that this block was restating at the dev. The file already uses this pointer idiom three times (生产侧条款在 os-dev 定义,…契约住 os-dev 定义,…dev 侧对价住 os-dev 定义).If a reviewer would rather keep any one of those, the payment is swappable:
references/dispatch-runbook.md:158,:62and:167are each a rule already stated inSKILL.md(:287,:80,:583respectively), and:167was deliberately NOT taken because it is rung ③ of an enumerated ladder that would read truncated without it.The copyable query and its control, verified against the live board
The control was run in this worktree and lights:
The sharper reading was exercised too, to prove it is an operable read and not a slogan. Fetching that head into a ref this worktree owns and reading the release-staged changelog on it shows the pending entries already folded in:
So for any card whose fix corrects a sentence in a staged entry, the head's
CHANGELOG.mdis the direct answer to 「离永久还有多远」, while the staged/not-staged bit is already spoken for and carries almost nothing.Gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackwas derived in this worktree with no paths passed; its stderr names the tree it answered for (objectstack-ai/objectstackat758ac4097). All 14 derived commands were run, exit codes captured before any pipe:node scripts/check-closing-keyword-parity.mjsnode scripts/check-closing-keyword-parity.mjs --self-testnode scripts/check-comment-mask-corpus.mjspnpm --filter @objectstack/lint run check:doc-formula-expressionspnpm check:agent-test-spellingpnpm check:doc-authoringpnpm check:driver-memory-censuspnpm check:nul-bytespnpm check:pm-governed-mergespnpm check:pm-skill-id-lintpnpm check:pm-skill-ratchetpnpm check:refd-timer-probepnpm check:skill-frame-syncpnpm check:watch-hint-literalVerdict lines worth quoting:
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/dispatch-runbook.md is 241 lines (ceiling 241; headroom 0).✓ check-skill-id-lint: 27 file(s) clean (pattern /#[0-9]{3,}/g).— this is why the lit control in the charter text is thegit ls-remotehit and not a PR number: a 3-or-more-digit#citation in these files is red, so the control had to be one that carries no card id.check-nul-bytes: OK (scanned 8476 text file(s) ... no raw ASCII control bytes).pnpm --filter @objectstack/lint run check:doc-formula-expressionsfirst exited 3 —PREREQUISITE NOT MET, two unbuilt workspace packages, nothing measured. It was not recorded as a failure: the two packages were built under the shared verify lock (os-verify-lock: VERDICT command-exit 0) and the gate re-run to a real exit 0. Reconciliation:node scripts/pm/dispatch-gates.mjs --ran …prints14 derived, 14 run, 0 NOT-MEASURED, 0 UNRUNanda DERIVED zero — all 14 recorded an exit code and none of them is 3.Union re-run anchor: the gate sweep above was taken on
df83eb3c1, the final commit on this branch.No changeset.
.claude/**publishes nothing from any released package, which is the documentedskip-changesetcase; the derivation's own note that 14 further families "apply once this card's changeset exists" is consistent with there being none. Theskip-changesetlabel is applied on this PR and read back.Follow-up the PM folds into the next SKILL.md PR (work item B, deliberately NOT done here)
A reader who only reads
SKILL.mdwill not find the new clause.SKILL.mdis out of scope on this card — PR 17837 is open on it at the human terminal, andSKILL.md:34/:683are prohibitions that must stay byte-identical — so no pointer was added there. If the PM wants one, the natural spot is besideSKILL.md:34's release prohibition, one line: the criterion for whether a release is staged lives inreferences/dispatch-runbook.md, head-branch based.Out of scope, noted, not filed
SKILL.mdandreferences/core-rules.md. It is complementary, not overlapping: it constrains what a control must be, this PR supplies the missing instrument. No text is duplicated between the two diffs. Carrier: PR 17837's author.references/dispatch-runbook.mdcarries three further rules that are already stated verbatim in substance inSKILL.md(:158vsSKILL.md:287,:62vsSKILL.md:80,:167vsSKILL.md:583). Under this file's own landing convention ("no rule already stated in SKILL.md") they are payment available to a future addition here. Not a defect, not filed; carrier: the next PR that needs headroom in this file.维护者速读(草稿)
改了什么 — 分诊章程里加了四行:怎么判断「版本发布是否已经上膛」。判据是发布 PR 的 head 分支名(
changeset-release/main),给了一条可以直接照抄的查询和一条必中的对照命令;明写 ⛔ 不许拿 PR 标题当判据(两个仓的标题本来就不一样,而且是 action 配的);并且指出真正有用的那个读数不是「发不发」,而是「这张卡的 changeset 有没有已经折进那个 head 的CHANGELOG.md」。四行的额度靠删掉同一个文件里五行只讲道理、或者在别处已经有唯一出处的重复条款换来,文件行数一行没涨,天花板没动。为什么改 — 一个席位需要这个判断时,自己现场发明了一个查询(按标题找
Version Packages的 PR),而那个查询在两个仓、任何时刻都恒返 0;它渲染出来的答案恰好是「发布没上膛,慢慢来」——错在放行这一侧。纪律本来就在(零必须配点亮对照),缺的是那件仪器本身。⛔ 未断言那次误判造成了实际损失。风险与代价(含回滚) — 纯文本改动,不碰任何脚本、门禁、台账,也不改任何禁令(不跑发布、不催发布 PR 原样保留)。代价是同文件里删了两行「理由」和一段三分区义务的第四份副本(单源仍在
SKILL.md与 dev 定义里);如果您觉得其中某一行该留,PR 正文里列了三处可替换的付账点。回滚 = 单 commit revert,零连带。席位意见 — (留空,待席位契约复核定稿)
你要做的 — 只需判两件:① 这四行该不该放在「落卡与裁决记录细则」这一节(理由:那是章程里唯一管「落到卡上的读数必须配点亮对照」的一节);② 删掉的那五行里有没有您想留的。判完人工合并即可 ——
.claude/**是受管面,本 PR 保持 draft,⛔ 席位不翻 ready、不入队。Generated by Claude Code