Skip to content

Commit 1a20cbc

Browse files
feat(pm): the workflows row lands Tier S unless its diff trips a release path or a C2 trigger (#31628)
domain:skills#2 · zhuangjianguo · session_01QsR2jT34CXs5fCn3BDirZw <!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} --> _Requested by **Steedos** · [project thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9UbbQPUFkmB2t4gDe9p5ntfxAL)_ Fixes #31538 Clause-②: no Metadata-protocol: none ## 维护者速读 - **改了什么**:objectstack 仓的 `.github/workflows/**` 改为按 diff 内容定落地档。6 个发布/部署/写中继文件,以及改权限、密钥、新 action、删 job、改必查名、新 continue-on-error、改 if 的改动仍需你批(Tier H);其余改动凭达档复核 PASS 由席位落地(Tier S)。队列守卫、AGENTS.md §14、pm-dispatch 技能同步改。 - **为什么改**:落实 #31538 的裁决 C(记录 6722205630):超时、缓存键、路径过滤、已在用 action 的版本升级这类小改不再排队等人批;能关掉别的门禁的改动照旧人合。 - **风险与回滚**:风险是把危险改动误判成 S。凡读不出 diff、解析不了、没有基线、或拿不准的情况一律判 H(清单见 Acceptance notes)。回滚 = revert 本 PR,工作流行回到整行 Tier H。 - **先看**:`scripts/pm/check-governed-merges.mjs` 的 `workflowDiffReasons` 与 `WORKFLOW_TIER_H_FILES`;`scripts/pm/check-governed-queue-guard.mjs` 的 `attachWorkflowReadings`;`AGENTS.md` §14 改的两行。 - **两分钟验证**:`node scripts/pm/check-governed-merges.mjs --self-test && node scripts/pm/check-governed-queue-guard.mjs --self-test`,预期两行 ✓,分别 609 条与 433 条。 - **需要你做的**:暂无。本 PR 整体 Tier H,contract review owed;复核 PASS 后席位请你批准。 ## What changes 1. **`scripts/pm/check-governed-merges.mjs`** — the `workflows` register row gains `split: { repos: ['objectstack'], reader: 'readWorkflowDiff' }`. Its `tier` stays H, so every path-only reader (and objectui, cloud) keeps answering H. With a reading of the diff, `applyWorkflowSplit` sets the row's tier per PR: - **Tier H by path** (`WORKFLOW_TIER_H_FILES`, any edit): - `release.yml`: publishes the packages and queues the `release` deployment (Prime Directive #15). - `docker-publish.yml`: pushes the runtime image (`push: true`, `packages: write`). - `framework-build-base.yml`: pushes the framework build base image (`push: true`, `packages: write`). - `docs-deploy.yml`: deploys the docs site (`vercel deploy --prebuilt`, the deploy token). - `checklist-status.yml`: publishes the checklist status pages to the wiki (`contents: write`). - `fleet-write.yml`: the fleet's write relay and its App key. Biased to H: it holds the credential; it is not a release. - **Tier H by diff (C2)**: an added or changed `permissions:`; a `secrets` or job-token line (`github.token` in any case, any `github[…]` index, `toJSON(github)`) added, changed or moved; `pull_request_target`; a `uses:` (or container image) not used anywhere under `.github/workflows` or `.github/actions` at the merge base; a deleted job, a changed literal check-run name, or a changed `needs:` (added or lost); a new `continue-on-error`; an `if:` the base does not hold for the same owner with the same text, unless its job is new on the head. - **Tier S** otherwise. - The reader is a dependency-free line-model YAML reader, because the guard's `pull_request` leg runs before any install. It **fails closed**: tabs, anchors, aliases, tags, merge keys, multi-document markers, flow mappings other than `{}`, flow collections spanning lines, unclosed quotes, double-quoted escapes (`\x`, `\u`, `\U`…), lines led by a YAML indicator (`? permissions`) and a child under a node with a scalar value are all refused, and refused is H. - `--branch` and `--pr` read the diff (`--pr` only when the checkout holds both commits). `--test` has paths only, so it always says H. Verdicts print one split line naming the reasons. 2. **`scripts/pm/check-governed-queue-guard.mjs`** — `attachWorkflowReadings` reads each queued commit against its first parent (`merge_group`) or the merge base (`pull_request`). `decomposeGovernedWork` then takes the tier from the reading. A measured Tier S entry goes to the existing review-of-record leg. A commit it could not read, including a second commit of the same PR, stays Tier H. 3. **`AGENTS.md` §14** — the Tier H and Tier S clauses name the split. Two lines are edited in place; no line was added and nothing was re-wrapped. 4. **`.claude/skills/pm-dispatch/SKILL.md`** — 〈受管面两层〉 now names the split in one new line. That line is paid for by deleting `- 批准判定单源 = 队列守卫常量 GOVERNED_APPROVERS…不卡 commit_id`, whose surviving copy is `AGENTS.md:288` ("authorized APPROVED review by an account in `GOVERNED_APPROVERS`, on ANY commit and not dismissed"). The file stays at its 319-line ceiling, and every line is ≤120 B. 5. **`.github/CODEOWNERS` is unchanged.** The mirror self-test reads each row's register `tier`, and that tier is still H, so the mirror still requires `/.github/workflows/`, and it stays green. CODEOWNERS is a static path file that cannot read a diff. Routing a Tier S workflow PR to the approvers is a request, not a barrier, so this errs toward over-summoning, which is the safe direction. ## Why Ruling record 6722205630 (letter C, maintainer 「同意」) on #31538: split workflow landing, keep the edits that can switch other gates off at Tier H, and move the rest to Tier S. ## Tests - `check-governed-merges --self-test`: 543 → 609 assertions. New battery `⭐ the workflows split…`: 66 cases. Battery floor 35 → 36. - Trigger → pin: - permissions → `C2-permissions-added-is-H`, `C2-a-changed-permissions-key-is-H` - secrets → `C2-a-secrets-reference-added-is-H`, `C2-a-github-token-reference-added-is-H` - pull_request_target → `C2-pull_request_target-is-H` - new `uses:` → `C2-a-uses-no-workflow-on-the-base-uses-is-H` - deleted job → `C2-a-deleted-job-is-H` - check-run name → `C2-a-literal-check-run-name-changed-is-H` - continue-on-error → `C2-a-new-continue-on-error-is-H` - disabling `if:` → `C2-an-if-that-disables-a-step-is-H`, `C2-an-if-that-disables-a-job-is-H`, `⛔ M1-a-renamed-gate-step-given-if-false-beside-a-dummy-under-the-old-name-is-H`, `⛔ M1-a-gate-step-re-keyed-by-an-id-and-given-if-false-is-H`, `⛔ M1-a-new-step-with-its-own-if-inside-an-existing-job-is-H` - changed `needs:` → `biased-a-needs-that-lost-a-job-is-H`, `⛔ S1-a-needs-added-on-an-existing-job-is-H` - reader refusals → `⛔ M2a-a-flow-mapped-step-is-refused-and-H`, `⛔ M2b-a-double-quoted-escape-spelling-a-key-is-refused-and-H`, `⛔ M2b-an-escape-inside-a-value-is-refused-too`, `⛔ M2d-an-explicit-key-line-is-refused-and-H`, `⛔ M2d-a-child-under-a-node-with-a-scalar-value-is-refused-and-H` - credential spellings → five `⛔ M2c-a-credential-spelled-…-is-H` pins (`Secrets.`, `SECRETS.`, `github['token']`, `GitHub.Token`, `github . token`) and two `⛔ D2-the-job-token-reached-as-…-is-H` pins (`toJSON(github)`, `github[format(…)]`) - a gate moved out of an existing job → `⛔ D1-a-gate-step-moved-into-a-new-job-with-if-false-is-H`, `⛔ D1-a-gate-step-moved-into-a-new-job-behind-an-opt-in-needs-is-H`, `⛔ D1-a-uses-moved-out-of-an-existing-job-is-H` - path → `six-files-are-Tier-H-by-path-release-docker-base-image-docs-wiki-and-the-write-relay`, `a-pinned-file-is-H-even-on-a-comment-only-edit` - Near-misses, each Tier S: a moved `if:` that disables nothing, a `uses:` bump of an action already in use, a timeout edit, a path-filter edit, a shard count inside a computed matrix name, a cache-key edit, a comment edit, and a new job with a fresh name and its own `if:`. Controls that must still parse: `{}`, an expression value, a plain-scalar continuation. - Fail-closed pins: no reading, an unmeasured reading, no base, git throws, unparseable YAML, a new file, a deleted file, a non-YAML file. - `check-governed-queue-guard --self-test`: 403 → 433 cases. New battery `⭐ the workflows split at the queue (ruling record 6722205630)`: 30 cases. Battery floor 29 → 30. Ablation: raising the battery's pin to 31 turns the run red. - An S reading makes the entry Tier S and clears on a valid record with zero approvals, through the real recognisers. - The same entry is refused with no record, and a Tier H reading with only a record is refused. - A second commit of the same PR that was not read makes the entry H, and objectui and cloud stay H. - The fake-git reader takes the first parent on `merge_group` and the merge base on `pull_request`, reads the inventory once, and treats an unresolved parent as H. ## Acceptance notes - **Replay on the last 40 workflow-touching merges** (37 had workflow paths on the first parent; re-run after each review round, same 13): 13 come out Tier S at the workflow row (#27115, #27709, #30714, #27018, #27122, #27400, #27571, #28089, #29326, #30869, #31086, #31133, #31138) and 24 stay Tier H. #27400 and #31133 stay Tier H as whole PRs because they touch other Tier H paths. The most common H reasons were an `if:` not held on the base (31 hits), a changed `needs:` (12, the `schedule-gate` wiring), a new `continue-on-error` (9, the lint.yml collector idiom), a gate or action no longer held by an existing job (9, lane rebalancing), a pinned path (8), a dropped gate invocation (6) and permissions (3). - **Cases biased to Tier H**, because this surface can switch the other gates off: - a changed job, step or workflow that holds a secret or a write token - an added `|| true`, `set +e`, `exit 0`, or an `OS_SKIP_` / `OS_DISABLE_` / `OS_ALLOW_` variable - a dropped gate invocation (`check:*`, `scripts/*.mjs`, `pnpm <script>`, `turbo run X`, vitest, eslint, tsc, playwright, lychee), from the file or from an existing job (a gate moved into a new job that never runs) - a dropped `uses:` or image, from the file or from an existing job - a changed `needs:`, added or lost - a changed trigger set - a changed workflow name - a new job whose check-run name is computed or collides with an existing one - a new, deleted or non-YAML workflow file - `fleet-write.yml` and `checklist-status.yml` by path - any `if:` the base does not hold for the same owner and text, inside a job that already existed (a step's owner is a name the author picks) - container images treated like `uses:` - `--test` mode always, and `--pr` unless the checkout holds both commits - objectstack's `ui/.github/workflows/**` row (not split) and the objectui and cloud rows - **Known limit, S by the ruling:** the text of a `run:` / `shell:` edit is not judged beyond a dropped gate token or an added risky pattern (`echo "pnpm check:x"`, `|| :`, `shell: bash {0}` read S); the contract review of record is the control. - **Follow-ups, all outside this card's file surface:** - `.github/actions/**` is not a register row yet feeds the "already in use" inventory (review N3); the seat files the card. - A cross-repo card is owed for item 4 of #31538 (cloud and objectui). The seat files it. - `scripts/pm/fleet-write/execute.mjs` `governedReviewPlan` is still path-only, so a Tier S workflow PR still has the approvers requested on it. That is an over-summon, not a barrier. - No new gate, no gate skipped or made report-only, no required context dropped, and no merge-queue setting changed. ## Verification - Head 0952245 (both review rounds' fixes, with main merged at 8784ccb) — `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 46 commands. All 46 exited 0, and `--ran` reconciled 46 derived, 46 run, 0 NOT-MEASURED, 0 UNRUN. `check:doc-formula-expressions` ran after `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint`. `eslint` on the two scripts is clean. - All 32 workflows and 3 local actions on the tree still parse under the stricter reader, and a differential against the `yaml` library shows 0 files with differences. - At the earlier head 268167f, I also ran the roster gates whose roster is under a touched directory. Ten exited 0. `check:published-readme-exports` exited 3 (NOT MEASURED: it needs every published package built), and this diff publishes nothing. ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (not touched) - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `eslint` on the two changed scripts passes (the whole-repo `pnpm lint` is left to CI). - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. (publishes nothing: `skip-changeset`) - [x] 6. `packages/spec` touched: its generated artifacts are regenerated and committed. (not touched) - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English (the `## 维护者速读` block is Chinese by os-dev.md's rule). - [x] The *Before Submitting* list in CONTRIBUTING.md is done. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01QsR2jU8C3iu8fsXdU4Rm8o --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent fe88ecd commit 1a20cbc

4 files changed

Lines changed: 988 additions & 22 deletions

File tree

‎.claude/skills/pm-dispatch/SKILL.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,15 +192,15 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报
192192
- 草稿归 dev:PR 正文带 `## 维护者速读` 六行(见 os-dev.md),中文、业务角度,不写席位意见。
193193
- 终稿 = 席位对照自己读的 diff 校正六行、加席位意见行,置顶席位记录;维护者只读评论。
194194
- `pm:awaiting-merge` 只挂 PR、不入六态,与请审同为等人批清单,随获批或撤回判决离开。
195-
- 批准判定单源 = 队列守卫常量 `GOVERNED_APPROVERS`:授权账户 APPROVED 即算,⛔ 不卡 `commit_id`。
196195
- 批准后再推亦不过期;席位落地 = 过落地前检、清标、ready、auto-merge,踢出/变基同法。
197196
- ③ 请审 = 席位交棒:ACCEPT 与现 head 同形 PASS 俱在案,同轮中继 `pr_request_reviewers` 请审批人。
198197
- 作者是审批人 ⇒ `assign` 它、请其余(请它必 422);⛔ 永不请席位自身账号;Tier S 不交人。
199198
- `pr_create` 派不请;`pr_ready` 只补交棒漏;非例外 head 移 ⇒ 撤挂回等;脱中继 PR 自读请/派。
200199
- 速读「需要你做的」求批点名 PASS 评论 id+`Head-sha`;无 PASS ⇒ 写 contract review owed 不求批。
201200
- ④ 轮报单列 awaiting a human merge 并现读请审人;⛔ 未请审不在 chat 报「等你批」,先补请。
202201
- skills 车道自有 PR:纯代码面如 `scripts/pm/` 由本席按达档自审(清单不减)后落地。
203-
- 受管面两层:Tier S = `.claude/**` 全树,余皆 Tier H 等人批;S 经达档复核 PASS 后 ready → 入队。
202+
- 受管面两层:Tier S = `.claude/**`+下行 S 面,余皆 Tier H 等人批;S 经达档 PASS 后 ready → 入队。
203+
- 本仓 `.github/workflows/**` 由 `readWorkflowDiff` 定档:发布路径、C2 触发、拒读或未读 ⇒ H,余 S。
204204
- 入队资格:每 check 绿或预期 skip,⛔ 非必查子集;名单 check-expected-skips.mjs 只判 objectstack。
205205
- 非必查红是真缺陷或坏门,归 PM 入队前处置;第三种按设计而红,三条全立才可带红入队:
206206
- 源码自述 pushed 分支上按设计而红、不跑 `merge_group`、PR 评论记明门与因,缺一即否。

‎AGENTS.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,10 +284,10 @@ See `ui/AGENTS.md` for the app-id / localStorage / auth gotchas.
284284
auto-merge, ⛔ never flip it out of draft to make any of those possible — judged on the PR's **file list**, not
285285
its description; a **mixed diff is not a proportion question**, one path hit is enough; to land the rest, split off
286286
the governed files. **The landing is tiered by the register; one Tier H path makes the whole PR Tier H.** **Tier H**
287-
(人合: every register row except `.claude/**`): those four lift only for an
287+
(人合: every register row except `.claude/**` and Tier S workflow edits): those four lift only for an
288288
authorized APPROVED review by an account in `GOVERNED_APPROVERS`, on ANY commit and not dismissed; that word is
289289
spent once per PR — the OWNING seat then lands it, later pushes included; the click stays the maintainer's.
290-
**Tier S** (席内达档复核落地: all of
290+
**Tier S** (席内达档复核落地: objectstack workflow edits `readWorkflowDiff` reads as Tier S, and all of
291291
`.claude/**`): those four lift once the PR thread or its card carries a `## Contract review` record for the PR's
292292
current head with `Served-tier: CONTRACT_REVIEW_TIER` and a PASS verdict and every check is green — the owning
293293
seat then lands it through the queue; the post-merge audit is the compensating control. A PR whose only governed

0 commit comments

Comments
 (0)