Skip to content

docs(pm): the charter states how to test whether a release is staged — by head branch, never by title - #17850

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-17830-release-staged-criterion
Sep 12, 2026
Merged

docs(pm): the charter states how to test whether a release is staged — by head branch, never by title#17850
os-zhuang merged 1 commit into
mainfrom
claude/issue-17830-release-staged-criterion

Conversation

@claude

@claude claude Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

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 branch changeset-release/main is 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's CHANGELOG.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/main at 758ac4097 (all four hold)

  1. The gap is real. 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:34 and SKILL.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 including references/dispatch-runbook.md, so the instrument reads the corpus the zero was taken over.
  2. The standing release PR answers the head-branch query. GET /repos/objectstack-ai/objectstack/pulls?state=open&head=objectstack-ai:changeset-release/main returns HTTP 200 with exactly one element: PR 17076, title chore: version packages, head changeset-release/main, state: open, draft: false, author github-actions[bot], created 2026-09-09T06:17:15Z. One hit per repo, as the card says.
  3. Both candidate carriers are at headroom 0. Read from the gate's own map rather than from the card: references/landing-operations.md 69 lines / ceiling 69, references/dispatch-runbook.md 241 / 241, MAX_LINE_BYTES = 120. SKILL.md (812/812) was left untouched as instructed.
  4. No open PR touches either carrier. All 22 open PRs' file lists read at 2026-09-12T12:2xZ: the only pm-dispatch paths in flight are SKILL.md + references/core-rules.md (PR 17837), references/decision-analysis.md (PR 17515) and references/platform-readings.md (PR 17803). references/dispatch-runbook.md is free.

Carrier chosen: references/dispatch-runbook.md, section 「落卡与裁决记录细则」

Both candidates were read in full first. landing-operations.md declares 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 priority or a pm: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:

B line
117 - 发布窗口判据:已上膛 = 开着的 head ...changeset-release/main... PR,...is:pr is:open head:changeset-release...。
96 - 点亮对照 ...git ls-remote origin changeset-release/main... 必中;⛔ title 永不是判据。
119 - 两仓 title 不同、由 action 配置:objectui ...chore: release packages...、objectstack ...chore: version packages...。
119 - 上膛与否不足:真判据是本卡 changeset 已否折进该 head ...CHANGELOG.md...,即「离永久还有多远」。
94 - 三分区各自的 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 in SKILL.md:458460 (取卡全序: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.
  • The three-line 三分区 dev-obligation block (64 + 119 + 73 B, section 「派发词构造细则」) collapsed to one pointer. That block was a fourth copy: SKILL.md:531 already carries the zones with their obligations in the parenthetical (裁决(不可重裁)/ PM 机制假设(须实测,鼓励证伪)/ PM 建议的路线(可选,实测优先)), references/core-rules.md:114 carries the PM-side half, and .claude/agents/os-dev.md carries 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, :62 and :167 are each a rule already stated in SKILL.md (:287, :80, :583 respectively), and :167 was 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

is:pr is:open head:changeset-release          # 1 hit in objectstack (PR 17076), 1 in objectui
git ls-remote origin changeset-release/main   # the lit control -- must print a ref

The control was run in this worktree and lights:

c26a619010289accb1de9d206a325bb969f5b64e	refs/heads/changeset-release/main

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:

git fetch origin changeset-release/main:refs/os-dev-17830/relhead -f
git show refs/os-dev-17830/relhead:packages/spec/CHANGELOG.md
  -> # @objectstack/spec / ## 17.5.0 / ### Minor Changes / - 7382c5d: feat(spec): ...

So for any card whose fix corrects a sentence in a staged entry, the head's CHANGELOG.md is 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/objectstack was derived in this worktree with no paths passed; its stderr names the tree it answered for (objectstack-ai/objectstack at 758ac4097). All 14 derived commands were run, exit codes captured before any pipe:

exit command
0 node scripts/check-closing-keyword-parity.mjs
0 node scripts/check-closing-keyword-parity.mjs --self-test
0 node scripts/check-comment-mask-corpus.mjs
0 pnpm --filter @objectstack/lint run check:doc-formula-expressions
0 pnpm check:agent-test-spelling
0 pnpm check:doc-authoring
0 pnpm check:driver-memory-census
0 pnpm check:nul-bytes
0 pnpm check:pm-governed-merges
0 pnpm check:pm-skill-id-lint
0 pnpm check:pm-skill-ratchet
0 pnpm check:refd-timer-probe
0 pnpm check:skill-frame-sync
0 pnpm check:watch-hint-literal

Verdict 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 the git ls-remote hit 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-expressions first exited 3PREREQUISITE 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 … prints 14 derived, 14 run, 0 NOT-MEASURED, 0 UNRUN and a 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 documented skip-changeset case; the derivation's own note that 14 further families "apply once this card's changeset exists" is consistent with there being none. The skip-changeset label 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.md will not find the new clause. SKILL.md is out of scope on this card — PR 17837 is open on it at the human terminal, and SKILL.md:34 / :683 are prohibitions that must stay byte-identical — so no pointer was added there. If the PM wants one, the natural spot is beside SKILL.md:34's release prohibition, one line: the criterion for whether a release is staged lives in references/dispatch-runbook.md, head-branch based.

Out of scope, noted, not filed

  • PR 17837 (open, at the human terminal) is sharpening the general half of the same discipline — a zero-hit control must share its claim's subject and failure mode — in SKILL.md and references/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.md carries three further rules that are already stated verbatim in substance in SKILL.md (:158 vs SKILL.md:287, :62 vs SKILL.md:80, :167 vs SKILL.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

…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
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 12, 2026
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Sep 12, 2026
@claude

claude Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

维护者速读

改了什么 — 派发细则(references/dispatch-runbook.md)「落卡与裁决记录细则」一节加四行:怎么判断「版本发布是否已上膛」。判据是发布 PR 的 head 分支 changeset-release/main(查询 is:pr is:open head:changeset-release,对照 git ls-remote origin changeset-release/main 必中);明写 ⛔ 不拿 PR 标题当判据——两仓标题不同(chore: release packages / chore: version packages)且由 action 配置;再指出真正有用的读数是「这张卡的 changeset 有没有已折进该 head 的 CHANGELOG.md」,即离永久还有多远。四行额度靠删同文件里两行「理由」和一段三分区义务的第四份副本(单源仍在 SKILL.md :531 与 os-dev 定义 :182–184)换来,241 行不变,天花板不动。

为什么改 — objectui#9065 复核时一个席位现场发明了「找标题为 Version Packages 的 PR」这条查询,它在两仓任何时刻都恒返 0,渲染出的答案恰好是「窗口没关,慢慢来」。零配对照的纪律本来就在,缺的是仪器本身;#17026 是窗口关掉后错句永久留在 CHANGELOG 的实测先例。

风险与代价(含回滚) — 纯章程文本,不碰脚本、门禁、禁令(不跑发布、不催发布 PR 原样);删掉的五行在 PR 正文逐条列出,若想保留某行,正文给了三处可替换的付账点。回滚即 revert。

席位意见 — 接受(ACCEPT 5645955481,契约档复核)。一条后续由本席承担:SKILL.md 里加一行指向此条款的指针,搭下一张 SKILL.md 的 PR(PR #17837 落地后的 #17728)。

你要做的 — 受管面(.claude/**),只能人工合并:判两件——① 四行放在「落卡与裁决记录细则」是否合适;② 删掉的五行有无想留的。合并 PR #17850 即可。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 12, 2026 15:26
@os-zhuang
os-zhuang enabled auto-merge September 12, 2026 15:26
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 12, 2026
Merged via the queue into main with commit 2f1fec6 Sep 12, 2026
36 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-17830-release-staged-criterion branch September 12, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation needs-user-decision size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

分诊章程没有「发布是否已上膛」的判据 —— 一个席位据此手打了一个两仓都永不命中的查询,读成了假放行

2 participants