Repository navigation
Commit 1a20cbc
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
- scripts/pm
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
192 | 192 | | |
193 | 193 | | |
194 | 194 | | |
195 | | - | |
196 | 195 | | |
197 | 196 | | |
198 | 197 | | |
199 | 198 | | |
200 | 199 | | |
201 | 200 | | |
202 | 201 | | |
203 | | - | |
| 202 | + | |
| 203 | + | |
204 | 204 | | |
205 | 205 | | |
206 | 206 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
284 | 284 | | |
285 | 285 | | |
286 | 286 | | |
287 | | - | |
| 287 | + | |
288 | 288 | | |
289 | 289 | | |
290 | | - | |
| 290 | + | |
291 | 291 | | |
292 | 292 | | |
293 | 293 | | |
| |||
0 commit comments