Repository navigation
Commit 4ddf6df
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoAqVfFyhsxKuFcEP9YTBj25)_
Part of #26137 (PR A of two: the CI comparison; PR B retires the
per-package records once this is green on `main`). Tier H
(`.github/workflows/**`).
Part of objectstack#25677.
Clause-②: no
Metadata-protocol: none
## 维护者速读(草稿)
- **改了什么:** `Build & E2E UI` 多了一步:用 `node
scripts/gen-sdui-manifest-node.mjs` 从本树重新生成
`sdui.manifest.json`,再和提交的文件逐字节比较,不一致就红,并打印差异和修复命令。`ci.yml` 的 `ui` 过滤器加了
turbo 的四个全局依赖文件,以及清单自己的四个文件。原来 lint 里按源码摘要判新鲜度的检查保留不动。
- **为什么改:** 摘要只读各 registry 包的 `src/`,看不见三类变化:解析器
`@objectstack/sdui-parser` 的改动、registry 运行时引用的 `@objectstack` 包的改动、两个排队
PR 合起来的效果。实测:在 `main` 上改 `manifestFromConfigs` 一行,现有检查仍是绿的,而重新生成的清单差了 87
行。现在 PR 和合并队列的合并树上都会重新生成并比较。
- **哪些原来能合的现在会被拒:** 只有清单确实过期的 PR。今天 `main` 重新生成与提交的字节完全一致。
- **代价:** 每次跑 ui 的 run 多约 3.6 分钟 runner 时间(27 个 `@object-ui` 包冷构建
3m25s,枚举 8s;36 个 `@objectstack` 任务从 Build UI Deps 回放)。今天 22 次绿 run 里 ui
尾部都比它长,所以墙钟时间增加 0。`Build & E2E UI` 超时按规则重算为 35 分钟。
- **风险与回滚:** 只改 CI 和文档,不发布任何包。回滚 = revert 本 PR。
- **你要做的:** Tier H,需要 GOVERNED_APPROVERS 审批。
## 席位核对
(left for the dispatch seat)
## Why
`check-sdui-manifest` (lint, every PR) judges the committed
`sdui.manifest.json` fresh when each registry package's `src/` digest
equals its one-line record under `scripts/sdui-manifest.sources/`
(#26051, #26120). That digest is blind to everything outside those
`src/` trees that moves the artefact:
- **the serialiser itself**, `@objectstack/sdui-parser`, which the
generator imports from `packages/sdui-parser/dist`. Since the lockstep
gate retired (#26221) nothing ties a parser edit to the records, and
after 2g PR 2 deletes `ui/packages/sdui-parser` the records stop
reaching any parser at all (#26137 comment 6420796812);
- **the `@objectstack` packages the registry imports at runtime**
(`spec`, `client`, `core`, `formula`, `types`), and any `package.json`
or lockfile change;
- **two queued PRs** that each leave the artefact unchanged and change
it together, the residual the maintainer accepted for #26120.
### Before: the gap on `main`, measured
On `main` 81bba6c, in `packages/sdui-parser/src/index.ts`
`manifestFromConfigs`, `isContainer: c.isContainer` → `isContainer:
c.isContainer ?? false`:
- `node scripts/check-sdui-manifest.mjs`: **exit 0**, "present, intact …
each package's digest current in its record";
- `node scripts/gen-sdui-manifest-node.mjs`: `sdui.manifest.json` **1
file changed, 87 insertions(+)**.
So a stale manifest passes today. With this PR, the same edit reds
`Build & E2E UI` on the PR, because `packages/sdui-parser/**` is in
`ui_consumers` and the step serialises through the parser the job just
built.
## What changes
### `ci.yml`, `Build & E2E UI`: the comparison
A new step, **"The committed SDUI manifest is the one this tree
generates"**, after "Build the @objectstack packages objectui consumes"
and before the Console build:
```bash
node scripts/gen-sdui-manifest-node.mjs
if ! git diff --quiet -- sdui.manifest.json; then
echo "::error file=sdui.manifest.json::…Run 'node scripts/gen-sdui-manifest-node.mjs' and commit what it writes."
git diff --stat -- sdui.manifest.json
git diff -- sdui.manifest.json | head -n 200
exit 1
fi
```
- **What it reuses:** the generator's turbo run is 63 build tasks. 36
are exactly the set `Build UI Deps` builds and hands over, and they
replay from the downloaded `ui-deps-turbo-cache`. The other 27 are the
`@object-ui` registry closure.
- **What it adds:** on 4 cores, the 27 build in 3m25s cold and the
enumeration takes 8s; with nothing moved the whole run takes 6s. The
output on `main` is byte-identical to the committed file (sha256
`1f6e1ccb925a…`, 106 components), and two runs agree.
- **Why this job:** it is required already, already replays the 36, and
is the shortest ui job (1.9–2.9 min across 22 green runs on 2026-10-26:
14 `pull_request`, 6 `merge_group`, 2 `push`). The ui lane's tail after
`Build UI Deps` was 8.4–14.2 min in the same runs, so the added wall
time measured 0 in all of them. Lint UI builds the 27 too, but it runs
on the `ui` output only, so a PR that changes only the parser or one of
the five packages would skip it (#26137 comment 6424273287).
- **What it compares:** only the artefact. The records the generator
rewrites beside it stay with `check-sdui-manifest` until PR B.
- **The Console build is unaffected:** `ui/apps/console/vite.config.ts`
aliases every workspace package to its `src/`, so the dist this step
builds does not reach it.
### `ci.yml`, the `ui` filter
| Added | Why |
|---|---|
| `tsconfig.json`, `tsconfig.base.json`, `tsconfig.test.base.json`,
`tsup.config.ts` | `turbo.json`'s `globalDependencies`. Every build task
hashes them, so they move what the ui jobs build. The digest never saw
them either. |
| `sdui.manifest.json`, `scripts/sdui-manifest.record.json`,
`scripts/gen-sdui-manifest-node.mjs`, `scripts/check-sdui-manifest.mjs`
| The artefact, its record, its producer and its offline gate. A hand
edit of the artefact, or a producer edit, now runs the comparison. |
The registry's runtime closure, walked over `dependencies` and
`peerDependencies` from the 17 seeds, is the 27 ui packages plus `spec`,
`client`, `core`, `formula` and `types`. All of them were under `ui/**`
or `ui_consumers` already. Cost of the additions: in the 30 days to
2026-10-26, 2 merged PRs moved one of the eight paths and no other ui
path (#26120, #25833); each would have run the ui lane once more.
### `ci.yml`, the ceiling
`Build & E2E UI` is re-derived by the rule in the comment above Lint UI.
The slowest successful run was 457 s; adding 213 s gives 670 s (11.2
min), so `max(33.5, 26.2)` ⇒ **35**, up from 25. The pin in
`ui/scripts/__tests__/turbo-cache-save-bound.test.ts` moves with it.
### Prose
- **`lint.yml`:** the `check-sdui-manifest` step comment says where the
regeneration now runs. The stale reference to the retired lockstep
neighbour goes.
- **`scripts/check-sdui-manifest.mjs` header:** "What this deliberately
does NOT do" and check 3's "What is NOT forced" now name the CI step
that does it.
- **`docs/releases-maintenance.md`:** one paragraph on the CI
comparison.
### Widening or narrowing
**This is a widening.** It adds a check, and no case that the current
check refuses passes now: the current check stays on, unchanged. The
step goes red only when the committed manifest differs from this tree's
regeneration. That is exactly a stale manifest, so nothing an author can
write is refused that is not stale.
## What PR B does, after this is green on `main`
It retires check 3 in-tree (the per-package digests) and
`scripts/sdui-manifest.sources/`. It also updates their readers:
- `scripts/gen-sdui-manifest-node.mjs`;
- `scripts/check-changeset-no-major.mjs` (L1368–1371, L4879, L4966);
- `docs/releases-maintenance.md`;
- `cut-rc.yml` and `release.yml` prose.
After that, PRs conflict only when the manifest's bytes really change.
Whichever of PR B and 2g PR 2 lands second rebases on
`scripts/sdui-manifest.sources/sdui-parser.json`.
## Verification
Head `d36dc4280`, on `main` `ff918954e`. 5 files, +79 / −23, one commit.
Tier H: `check-governed-merges --test` exits 3 for
`.github/workflows/ci.yml` and `.github/workflows/lint.yml` and 0 for
the other three paths.
- **The regeneration on this head:** `main` here already carries
#26211's parser. On `d36dc4280`, `node
scripts/gen-sdui-manifest-node.mjs` wrote **byte-identical** bytes:
sha256 `1f6e1ccb925a…`, 106 components, `git status` clean, no record
rewritten. So the new step should be green on this PR. With main moved,
that run rebuilt 62 of 63 tasks locally in 7m25s; in CI, `Build UI Deps`
supplies 36 of them.
- **The gap, before:** see "Before" above (main 81bba6c: gate exit 0,
regeneration +87 lines).
- **`check-sdui-manifest`:** `--self-test` 29 cases behave; the
production run is green.
- **Tests that read the job:**
`ui/scripts/__tests__/turbo-cache-save-bound.test.ts` and
`ensure-chromium-ready.test.ts` pass 52/52, with the 35-minute pin.
- **Workflows parse:** `ci.yml` and `lint.yml` both parse (14 jobs
each). `build-e2e-ui` reads `timeout-minutes: 35`, and the new step sits
between "Build the @objectstack packages objectui consumes" and "Build
the Console for E2E".
- **Gate sweep:** `node scripts/pm/dispatch-gates.mjs --commands`
derives 79 gates. They ran on `468450e19`, this commit before its rebase
from `4f7e0414a` to `ff918954e`; nothing on `main` between those touched
the five files. 78 exited 0. `check:dual-build-cjs-loads` exited 3
(prerequisite: no workspace `dist`), then exited 0 after `pnpm build`.
`--ran` reconciles 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN.
- **Push battery** (`GITHUB_ACTIONS=true GITHUB_EVENT_NAME=push node
scripts/pm/check-dispatch-gates.mjs`) on `468450e19`: 2164 cases pass, 0
fail, EXIT 0 (1586 s).
- **CI:** pending on `d36dc4280`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8b39b77 commit 4ddf6df
5 files changed
Lines changed: 79 additions & 23 deletions
File tree
- .github/workflows
- docs
- scripts
- ui/scripts/__tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
472 | 472 | | |
473 | 473 | | |
474 | 474 | | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
475 | 490 | | |
476 | 491 | | |
477 | 492 | | |
| |||
3734 | 3749 | | |
3735 | 3750 | | |
3736 | 3751 | | |
| 3752 | + | |
| 3753 | + | |
| 3754 | + | |
| 3755 | + | |
3737 | 3756 | | |
3738 | 3757 | | |
3739 | 3758 | | |
| |||
4063 | 4082 | | |
4064 | 4083 | | |
4065 | 4084 | | |
4066 | | - | |
| 4085 | + | |
4067 | 4086 | | |
4068 | 4087 | | |
4069 | 4088 | | |
| |||
4122 | 4141 | | |
4123 | 4142 | | |
4124 | 4143 | | |
| 4144 | + | |
| 4145 | + | |
| 4146 | + | |
| 4147 | + | |
| 4148 | + | |
| 4149 | + | |
| 4150 | + | |
| 4151 | + | |
| 4152 | + | |
| 4153 | + | |
| 4154 | + | |
| 4155 | + | |
| 4156 | + | |
| 4157 | + | |
| 4158 | + | |
| 4159 | + | |
| 4160 | + | |
| 4161 | + | |
| 4162 | + | |
| 4163 | + | |
| 4164 | + | |
| 4165 | + | |
| 4166 | + | |
| 4167 | + | |
4125 | 4168 | | |
4126 | 4169 | | |
4127 | 4170 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
966 | 966 | | |
967 | 967 | | |
968 | 968 | | |
969 | | - | |
970 | | - | |
971 | | - | |
972 | | - | |
973 | | - | |
974 | | - | |
975 | | - | |
976 | | - | |
977 | | - | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
978 | 976 | | |
979 | 977 | | |
980 | 978 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
85 | 85 | | |
86 | 86 | | |
87 | 87 | | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
88 | 98 | | |
89 | 99 | | |
90 | 100 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
85 | 85 | | |
86 | 86 | | |
87 | 87 | | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
92 | 93 | | |
93 | 94 | | |
94 | 95 | | |
| |||
98 | 99 | | |
99 | 100 | | |
100 | 101 | | |
101 | | - | |
102 | | - | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
108 | | - | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
109 | 114 | | |
110 | 115 | | |
111 | 116 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
77 | | - | |
| 77 | + | |
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| |||
0 commit comments