Repository navigation
Commit ebc2cdc
fix(pm): dispatch-gates derives fifteen whole-root lint gates from the diffs that can move them (#31291)
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1XVVos8qr5X7YcVK57du1fmt)_
Fixes #31257
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:`dispatch-gates --commands` 新增 15 条「按门禁自己的扫描范围 +
自己的第一道过滤」判定的派生行。改到某道全仓 lint 门禁真正会读、且能通过它自身预过滤的文件时(例如含 `getService`
的插件源码、含 `.json(` 的路由文件、新的 `sql-driver-*.ts` 分片),就把那道门禁派给卡。另有 2
道(`check:stack-collection-maps`、`check:filter-alias-parity`)经实测只读自己源码里写死的文件,路径派生早已覆盖,无需新行。
- 为什么改:这 18 道门禁在 CI 里每个 PR 都跑,但本地派生清单在改动不在它们「主包」时从不列出它们,开发者报「派生门禁全绿」后 CI
才红(#31214 就踩过一次)。
- 风险与回滚:只动 `scripts/pm/` 下的派生工具与自测,不改任何门禁检查什么,不动
workflow;最坏情况是多派生一道几秒的门禁,或漏派生(即现状)。回滚即还原本 PR。
- 先看:`scripts/pm/dispatch-gates.mjs` 的 `POPULATION_NETS` 与
`reachesPopulationNet`;`scripts/pm/dispatch-gates.data.mjs` 新增的 15 条
`CHANGE_KIND_ROWS`。
- 两分钟验证:`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack
packages/services/service-settings/src/settings-service-plugin.ts
packages/drivers/driver-sql/src/sql-driver-crud.ts`,预期多出 `pnpm
check:init-service-contract`、`check:settings-bind-window`、`check:startup-registry-verdict`
等(main 上没有)。
- 需要你做的:无,席位落地。
## What changes
Eighteen lint steps run on every PR (`lint.yml`, no `paths:` filter)
over a whole-root population, and `--commands` never handed them to a
card whose diff sat outside their home package: eleven print in the
declared-WIDE block and seven in the artifact-roster block, and the seat
ruling on #30763 keeps both blocks out of `--commands` wholesale. This
PR closes them family by family.
**Fifteen get a change-kind row (option a)**, each bound to its own
**population net**: the gate's own walk (roots, kept file names, skipped
names and directories, read off its source) plus the gate's own first
filter, the cheap pre-filter most of them run before their AST pass. Two
gates expose their per-file reader and keep no ledger, so the net
**imports** it instead of copying it (`check:runner-env-posture`:
`isProductSource` + `findRunnerEnvReads`; `check:error-code-casing`:
`findViolations`); both modules are dependency-free, so the tool still
runs with no install. A deleted population file is judged on the content
it HAD (HEAD's blob, else the blob before the deleting commit), so a
move or delete that strands a ledger row or a provider still counts,
while a path git never held does not.
| Gate | Block | Net (population · filter) | Hits / population at
07559ce | Recall vs the gate's own pass | Local wall |
|---|---|---|---|---|---|
| `check:init-service-contract` | WIDE | packages non-test `.ts` ·
`PREFILTER_TOKENS` (getService ×3, providesServices) | 217 / 4498 |
`--list` 31 files, 0 missed | 2.5 s |
| `check:settings-bind-window` | WIDE | same · + `trigger` | 657 / 4498
| `--list` 11, 0 missed | 4.2 s |
| `check:startup-registry-verdict` | WIDE | same · registry probes, open
registries, providesServices | 222 / 4498 | `--list` 29, 0 missed | 3.7
s |
| `check:optional-error-sink` | WIDE | packages non-test `.ts` ·
`CHANNEL_PREFILTER` | 1070 / 4498 | `--list` 204, 0 missed | 5.3 s |
| `check:resume-authority-declared` | WIDE | packages + examples ·
`defineActionDescriptor` | 19 / 4691 | `--list` 16, 0 missed | 1.1 s |
| `check:route-envelope` | WIDE | packages non-test `.ts` · `-routes.ts`
/ off-convention / domains by path, `.json(` by content | 160 / 4498 |
MODULES 56 files, 0 missed | 3.8 s |
| `check:verify-stand-in` | WIDE | packages + examples (tests included)
· guarded names read from `eslint.config.mjs`, verify src by path | 83 /
12003 | the census pre-filter itself | 2.0 s |
| `check:wildcard-fallthrough` | WIDE | packages non-test `.ts` · a
quoted `/*` | 143 / 4498 | `--list` 7, 0 missed | 2.0 s |
| `check:live-db-isolation` | WIDE | packages, apps, examples (tests
included) · `OS_TEST_{MYSQL,POSTGRES}_URL` | 101 / 12010 | 65 live
suites, 0 missed | 5.9 s |
| `check:runner-env-posture` | WIDE | the gate's `isProductSource` · its
`findRunnerEnvReads` (imported) | 0 / 4357 | the gate's own reader | 8.7
s |
| `check:meta-type-normalized` | WIDE | `packages/rest/src` non-test,
path only | 56 / 56 | the gate's own 56 files | 0.8 s |
| `check:tenant-chokepoint` | roster | `sql-driver-*.ts` listed in the
driver-sql src dir, path only | 36 / 36 | the gate's listing (39 = 3
drivers + 36) | 1.0 s |
| `check:authz-resolver` | roster | packages non-test TS · both grant
tables named | 62 / 4489 | its `queriesAllGrantTables` needs both | 2.3
s |
| `check:error-code-casing` | roster | packages `.ts/.tsx` · its
`findViolations` (imported) | 4 / 11748 | the gate's own reader (4
exempt) | 12.6 s |
| `check:object-def-param-keys` | roster | tracked `.ts` under a package
`src` · a class or an `as any` | 1248 / 4236 | `--list` 244, 0 missed |
7.0 s |
**Two are closed by measurement (option c):**
`check:stack-collection-maps` and `check:filter-alias-parity` read only
files their own source spells as literals (8 and 3), walk no root, and
the path derivation already matches the gate for every one of those
files. The census's "whole-root walk" signature for
`filter-alias-parity` was its AST `walk` generator.
**One is not closed here:** `check:published-readme-exports` (see
Acceptance notes).
## Why
#31214 paid a CI round trip on `check:error-code-provenance`, a family
of the same class; PR #31254 fixed three and #31257 holds the rest. A
dev report could read "all derived gates green" while CI went red on any
of these.
## Tests
New cases in `scripts/pm/dispatch-gates.self-test.mjs`, table-driven
over the fifteen nets (`NET_CASES`, one entry per net, held to
`POPULATION_NETS` key for key):
- **Per net:** a real diff shape is a hit (a plugin init lookup, a
settings `trigger`, a `hasService` probe, an optional-`error` sink type,
a pausing descriptor, a `c.json(` writer, a stand-in call in a verify
test, a wildcard mount, a live suite's URL read, a runner-variable
branch, a new REST source, the next `sql-driver-*` split, both grant
tables, a lowercase code, a class extending the SQL driver); the gate's
own walk exclusion is a miss; a population file without the filter is a
miss; a deleted file is judged on its prior content (hit and miss); a
path git never held is a miss; a path outside the roots is a miss; the
copied spellings are still in the gate's source (and for startup/sink
the token SET equals the gate's own Map/Set); exactly one row names the
gate, bound to this net; a live specimen derives the gate through the
whole table; the rendered lead says it needs no build and why no card
had it.
- **Imported readers** are identical to the gates' own functions; the
verify net reads the guarded names off the ESLint config and throws on a
config without the table; a docs-only page derives none of the fifteen.
- **Closures:** for both roster gates, every source file the gate reads
is a literal the path derivation already matches (8/8, 3/3), and the
gate walks no root.
- **Slow tier:** each net discriminates on the live tree, and every file
each gate's own `--list` names is inside its net (7 gates, 0 missed).
- **Pins moved:** the inherited-population census row 744 → 748 (four
import lines above it); two whole-table section-count pins (i18n bundle,
metadata form) now read through the entries naming `check:i18n`, because
the optional-sink and object-def nets fire on the same live files for
their own reason.
**Ablation** (one fast-tier run, three mutations through nested
`scripts/ablation-replace.mjs`, restore proven twice: blob == HEAD
`c0eee2c17012`, `git diff HEAD` empty), 47 of 2174 cases red, every one
named:
- walk exclusion removed from `inNetPopulation` ⇒ red "…the gate's walk
excludes X, so the net does too" for the 11 nets that exclude by file
name.
- token filter replaced by `true` in `reachesPopulationNet` ⇒ red "a
population file without the gate's filter is not a hit" for the 9 token
nets (the pattern and imported-reader nets are unaffected by that line,
as designed).
- prior-content read replaced by "any absent path counts" ⇒ red "a
deleted file is judged on the content it had" and "a path git never held
is not a hit" for all 13 content nets.
- also red: the existing "a test path emits the convention section"
count pin (the widened walk lets nets fire on test files).
## Acceptance notes
- **`check:published-readme-exports`: not derived; for a follow-up
card.** Its population is the 129 published markdown docs of public
packages outside `ui/`, plus the BUILT type entries of the 77 targets
(68 packages) their 268 import statements reach. A path net over those
packages is close to every package's source, so a precise net needs a
member-name reader (the names each doc imports, matched against
declarations in the reached package). The gate also needs those packages
built (exit 3 on an unbuilt worktree). Left out rather than shipped
imprecise.
- **What a net cannot see:** a gate that follows an import out of the
judged file (settings-bind-window resolves a hook name through one) can
be moved by the imported file alone; and a new token in a gate's
pre-filter widens the gate before the net, until the self-test's
spelling pin reds on it.
- **Precision trade:** `optional-error-sink` (24% of its population) and
`object-def-param-keys` (30%) are as wide as the gates' own first
filters; both are about 5–7 s and unconditional in CI.
- No `.github/**` edit; no change to what any gate checks.
## Verification
Gate union from `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` on this diff: 30 families, run on head
`81c8a785` (after merging `origin/main`), reconciled with `--ran`: "30
derived famil(ies) accounted for — 30 run, 0 NOT-MEASURED (a DERIVED
zero — all 30 recorded an exit code and none of them is 3)".
<details><summary>30 gates, exit codes captured before any
pipe</summary>
- `node scripts/check-closing-keyword-parity.mjs` (and `--self-test`),
`check-comment-mask-corpus.mjs`, `check-declaration-mirrors.mjs` (and
`--self-test`), `check-self-test-wired.mjs` (and `--self-test`),
`check-self-test-workflow-commands.mjs` (and `--self-test`),
`check-whole-set-label-write.mjs` (and `--self-test`),
`ci/plan-test-core-shards.mjs --self-test`: exit 0 each
- `pnpm check:agent-test-spelling`, `check:bash32-floor`,
`check:ci-filter-parity`, `check:cli-command-ids`,
`check:cross-package-test-inputs`, `check:declared-population-live`,
`check:driver-memory-census`, `check:entry-guard`,
`check:gitlink-declared`, `check:nul-bytes`, `check:parse-guard`,
`check:pnpm-filter-targets`, `check:pnpm-flag-spellings`,
`check:ratchet-remedy-authority`, `check:refd-timer-probe`,
`check:scripts-symbol-anchors`, `check:watch-hint-literal`: exit 0 each
- `pnpm check:pm-dispatch-gates`: exit 0, "✓ dispatch-gates self-test
(fast tier): 2174 cases pass; 8 slow section(s) deferred." (464.8 s)
</details>
- Full battery (`node scripts/pm/dispatch-gates.mjs --self-test`): on
head `81c8a785`, "✓ dispatch-gates self-test: 2483 cases pass." (fast
2174 cases in 422.9 s, slow 309 cases in 1282.6 s).
- `npx eslint --no-inline-config` on the three files: exit 0. `node
scripts/check-nul-bytes.mjs`: exit 0. No package touched, so no package
`lint`/`test`/`typecheck` is owed.
- CI families are read from this PR's check-runs, not re-run here.
`skip-changeset`: `scripts/pm/**` ships in no package.
## 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; `pnpm lint` passes (eslint on the three
files, exit 0).
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. Publishes nothing (`scripts/pm/**`), so `skip-changeset`; both
declaration lines are filled in.
- [x] 6. `packages/spec` not touched.
- [x] 7. No hand edits to generated docs, changelogs or release notes.
- [x] 8. Title, body and comments are in English (the maintainer brief
excepted, per the dispatch contract).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FEkQ5nVPVu6jXRZdmdUb8w)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 59d9815 commit ebc2cdc
3 files changed
Lines changed: 526 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
936 | 936 | | |
937 | 937 | | |
938 | 938 | | |
| 939 | + | |
| 940 | + | |
| 941 | + | |
| 942 | + | |
| 943 | + | |
| 944 | + | |
| 945 | + | |
939 | 946 | | |
940 | 947 | | |
941 | 948 | | |
| |||
1120 | 1127 | | |
1121 | 1128 | | |
1122 | 1129 | | |
| 1130 | + | |
| 1131 | + | |
| 1132 | + | |
| 1133 | + | |
| 1134 | + | |
| 1135 | + | |
| 1136 | + | |
| 1137 | + | |
| 1138 | + | |
| 1139 | + | |
| 1140 | + | |
| 1141 | + | |
| 1142 | + | |
| 1143 | + | |
| 1144 | + | |
| 1145 | + | |
| 1146 | + | |
| 1147 | + | |
| 1148 | + | |
| 1149 | + | |
| 1150 | + | |
| 1151 | + | |
| 1152 | + | |
| 1153 | + | |
| 1154 | + | |
| 1155 | + | |
| 1156 | + | |
| 1157 | + | |
| 1158 | + | |
| 1159 | + | |
| 1160 | + | |
| 1161 | + | |
| 1162 | + | |
| 1163 | + | |
| 1164 | + | |
| 1165 | + | |
| 1166 | + | |
| 1167 | + | |
| 1168 | + | |
| 1169 | + | |
| 1170 | + | |
| 1171 | + | |
| 1172 | + | |
| 1173 | + | |
| 1174 | + | |
| 1175 | + | |
| 1176 | + | |
| 1177 | + | |
| 1178 | + | |
| 1179 | + | |
| 1180 | + | |
| 1181 | + | |
| 1182 | + | |
| 1183 | + | |
| 1184 | + | |
| 1185 | + | |
| 1186 | + | |
| 1187 | + | |
| 1188 | + | |
| 1189 | + | |
| 1190 | + | |
| 1191 | + | |
| 1192 | + | |
| 1193 | + | |
| 1194 | + | |
| 1195 | + | |
| 1196 | + | |
| 1197 | + | |
| 1198 | + | |
| 1199 | + | |
| 1200 | + | |
| 1201 | + | |
| 1202 | + | |
| 1203 | + | |
| 1204 | + | |
| 1205 | + | |
| 1206 | + | |
| 1207 | + | |
| 1208 | + | |
| 1209 | + | |
| 1210 | + | |
| 1211 | + | |
| 1212 | + | |
| 1213 | + | |
| 1214 | + | |
| 1215 | + | |
| 1216 | + | |
| 1217 | + | |
| 1218 | + | |
| 1219 | + | |
| 1220 | + | |
| 1221 | + | |
| 1222 | + | |
| 1223 | + | |
| 1224 | + | |
| 1225 | + | |
| 1226 | + | |
| 1227 | + | |
| 1228 | + | |
| 1229 | + | |
| 1230 | + | |
| 1231 | + | |
| 1232 | + | |
| 1233 | + | |
| 1234 | + | |
| 1235 | + | |
| 1236 | + | |
| 1237 | + | |
| 1238 | + | |
| 1239 | + | |
| 1240 | + | |
| 1241 | + | |
| 1242 | + | |
| 1243 | + | |
| 1244 | + | |
| 1245 | + | |
| 1246 | + | |
| 1247 | + | |
| 1248 | + | |
| 1249 | + | |
| 1250 | + | |
| 1251 | + | |
| 1252 | + | |
| 1253 | + | |
| 1254 | + | |
| 1255 | + | |
| 1256 | + | |
| 1257 | + | |
| 1258 | + | |
| 1259 | + | |
| 1260 | + | |
| 1261 | + | |
| 1262 | + | |
| 1263 | + | |
| 1264 | + | |
| 1265 | + | |
| 1266 | + | |
| 1267 | + | |
| 1268 | + | |
| 1269 | + | |
| 1270 | + | |
| 1271 | + | |
| 1272 | + | |
| 1273 | + | |
| 1274 | + | |
| 1275 | + | |
| 1276 | + | |
| 1277 | + | |
| 1278 | + | |
| 1279 | + | |
1123 | 1280 | | |
1124 | 1281 | | |
1125 | 1282 | | |
| |||
0 commit comments