Skip to content

ci(sdui): retire the per-package SDUI manifest records; CI's regeneration holds freshness (#26137 PR B) - #26367

Merged
os-zhuang merged 3 commits into
mainfrom
claude/project-thread-6qe56u
Oct 27, 2026
Merged

os-zhuang merged 3 commits into
mainfrom
claude/project-thread-6qe56u

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Tesla · project thread

Closes #26137 (PR B of two: PR A #26315 put the regeneration in CI; this retires the per-package records it replaces). Tier H (.github/workflows/**).
Part of objectstack#25677.

Clause-②: no
Metadata-protocol: none

维护者速读(草稿)

  • 改了什么: 删掉 scripts/sdui-manifest.sources/ 下 26 个按包记录的源码摘要,以及 check-sdui-manifest 里比对这些摘要的第 3 项检查。清单是否新鲜,现在只由 ci(ui): regenerate the SDUI manifest in Build & E2E UI and compare it with the committed bytes (#26137 PR A) #26315 加的 CI 步骤判定:Build & E2E UI 重新生成 sdui.manifest.json 并逐字节比较,PR 上和合并队列的合并树上都跑。lint 里的检查保留存在性、形状和 sha256 防篡改。AGENTS.md 里仍在讲已退役 objectui 钉的那段改为现状(行数不变)。
  • 为什么改: 摘要记录是在 CI 不能重新生成清单时的替代品。它让两个改同一个 registry 包的 ui PR 在记录文件上冲突,哪怕谁都没改清单(i18n 最热,12 个开着的 ui PR 里有 5 个碰它)。本 PR 自己 rebase 到 main 时就撞上 7 个这样的冲突,而清单一个字节都没变。CI 重新生成后,PR 只在清单真的变了时冲突。
  • 哪些原来能合的现在会被拒: 没有。仍带 inTree.registryRecords 的旧记录会被拒,提示重新生成。
  • 哪些原来被拒的现在能合: 只改 registry 源码、不改清单的 PR 不用再提交记录文件。清单过期仍由 Build & E2E UI 拒绝,而且它看得见解析器、registry 引用的 @objectstack 包和两个排队 PR 合起来的效果,摘要看不见这些。
  • 风险与回滚: 只改 CI、脚本和文档,不发布任何包,清单字节不变。在本 PR 之前开的分支如果改过某个记录文件,rebase 时会遇到"修改/删除"冲突,删掉该文件即可。回滚 = revert 本 PR。
  • 你要做的: Tier H,需要 GOVERNED_APPROVERS 审批。

席位核对

(left for the dispatch seat)

Why

check-sdui-manifest held freshness with a source digest per registry package, recorded one line per package under scripts/sdui-manifest.sources/ (#26051). The digests existed because a PR author could not afford to regenerate the manifest on every push. They cost two things (#26137):

  1. Conflicts on records, not on the contract. Two PRs that touched the same registry package's src/ conflicted on that package's record even when neither changed sdui.manifest.json.
  2. A blind spot. No digest saw @objectstack/sdui-parser, the @objectstack packages the registry imports, or two queued PRs whose effect on the manifest only shows together.

#26315 made CI regenerate the manifest in Build & E2E UI and compare it with the committed bytes, on pull_request and on the merge queue's combined tree. It is green on main: the push run on 4ddf6df61 passed 50 of 53 check runs with 3 skipped and none failed, and Build & E2E UI ran the new step. The digests now only produce the conflicts. Rebasing this PR onto main hit seven of them: components, core, i18n, plugin-detail, plugin-grid, react and types had been re-recorded since, and the manifest's bytes had not moved.

What changes

scripts/check-sdui-manifest.mjs

  • Check 3 in-tree is gone. registrySourceDigests, readRegistryRecords, registryRecordPath, registryRecordLine, REGISTRY_RECORDS and the gate's copy of REGISTRY_MODULES go with it.
  • The in-tree leg keeps the artefact's presence and shape, the sha256 and component count against the record, and the inTree block (modulesRoot, objectuiWorkspaceVersion).
  • A record that still carries inTree.registryRecords is RED as a retired layout, the same way the single-digest fields from before devx(sdui): split scripts/sdui-manifest.record.json into one record per ui registry package, so ui PRs that touch different packages stop conflicting in the merge queue #26051 already are. That catches a branch cut before this PR that regenerated with the old generator.
  • READ_PATHS and ROOT_WATCH_HINTS drop ui/packages/** and the records directory. The gate reads neither now, so a registry package edit no longer derives it.
  • The success line says what it checked and names the CI step for freshness.
  • The pin mode is untouched.

Self-test: 29 rows → 21

The nine digest rows go with the code they tested:

  • a staged edit naming one package;
  • an unstaged edit;
  • tests and unreached packages;
  • a new workspace edge;
  • a new package;
  • a removed package;
  • a deleted record;
  • an other-artefact record;
  • a record out of its one-line form.

Two rows pin the new boundary, and each was ablated to show it bites:

Row Ablation Result
a record from the per-package layout is RED with the in-tree command drop registryRecords from the retired fields row reds
a producer run whose artefact did not move leaves the record as it was (replaces "re-records only the package whose sources moved") stamp today's generatedAt row reds
same re-read the @object-ui/core version instead of carrying it row reds

The carry row matters more now: the record is the one shared file left, so a producer that rewrote it on every run would make every pair of ui PRs conflict on it again.

SELF_TEST_BATTERY_FLOOR 29 → 21 matches the roster. The unused must-not-name column and the producer-list parity check (it existed only for the digest) are removed.

scripts/gen-sdui-manifest-node.mjs

  • No digests, no refusal of unstaged registry bytes (that existed because the digest read the index), no per-package records.
  • It no longer imports the gate, and drops git-env.mjs.
  • The build, the enumeration, the record's carry rule and the pin mode are unchanged.
  • The record's // note now names the CI step.

The records and the record

  • scripts/sdui-manifest.sources/ (26 files) is deleted.
  • scripts/sdui-manifest.record.json is regenerated. It loses inTree.registryRecords and takes the new note.
  • sdui.manifest.json is byte-identical (sha256 1f6e1ccb925a…, 106 components), and generatedAt is carried.

Readers

  • scripts/check-changeset-no-major.mjs: the comment, the real-build assertion and the record-only fixture name only the shared record.

  • lint.yml and ci.yml: the step comments.

  • docs/releases-maintenance.md: the manifest section, and the cut-rc step that said lint held freshness.

  • AGENTS.md (the dispatch seat asked for it here): the manifest paragraph still described the retired objectui pin. It said to run pnpm objectui:build, that scripts/check-sdui-manifest.mjs reds until you regenerate, and that objectui:bump and objectui:refresh print the step, but no objectui:* script exists since the cutover. It now names the in-tree command and the CI step. It is line-neutral: 5 lines stay 5, each ≤ 118 bytes, the file stays at 1112 lines, and check:pm-skill-ratchet and check:pm-governed-prose pass.

cut-rc.yml and release.yml name only the tracked artefact, so they need no change.

Widening or narrowing

For freshness, this is a narrowing of the lint gate, covered by a wider check that is already required. Every case the digests refused is a case where the committed manifest differs from what the tree generates, or a case where it does not:

  • The manifest differs: a registry source change that moves the manifest, or a combination of PRs. Build & E2E UI refuses it on the PR or in the queue.
  • The manifest does not differ: a source change that does not move it, or a new package or edge that adds no component. Refusing those was the conflict cost, not protection.

Build & E2E UI runs on ui || ui_consumers, and the registry's runtime closure is inside those filters (#26315's table), so no stale manifest that the digests caught reaches main.

Merge order

Verification

Head 15f5e2777, on main 77a52cfe8. 34 files, +198 / −687, one commit. 26 of the files are the deleted records. Tier H: check-governed-merges --test exits 3 for ci.yml, lint.yml and AGENTS.md, and 0 for the other five.

  • Regeneration: on this head, node scripts/gen-sdui-manifest-node.mjs rebuilt the registry after main moved (467 s) and left git status clean. sdui.manifest.json was byte-identical, and the committed record is exactly what it writes ("left unchanged … its date and version are carried").
  • check-sdui-manifest: --self-test 21 cases behave, and the production run is green: "present and intact (sha256 1f6e1ccb925a…, 106 components) … Not judged here: whether it is the manifest this tree generates."
  • Ablations: the three in the table above, each red, each restored.
  • Before the rebase, the same change stacked on PR A (75d1ea668, without the AGENTS.md paragraph) passed:
    • the derived sweep, 82 of 82 exit 0, with --ran reconciling 82 derived, 82 run, 0 NOT-MEASURED, 0 UNRUN;
    • the push battery, 2164 cases pass, 0 fail, EXIT 0.
  • On this head, the sweep and the battery are running and will be added here.
  • CI: pending.

🤖 Generated with Claude Code

https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS

…tion holds freshness (#26137)

Build & E2E UI regenerates sdui.manifest.json and compares it with the
committed bytes (#26315), on pull_request and on the merge queue's combined
tree. That makes the per-package source digests under
scripts/sdui-manifest.sources/ (#26051) redundant, and they were the reason
two ui PRs on one registry package conflicted even when neither moved the
manifest.

- check-sdui-manifest: check 3 in-tree (the per-package digests) is gone.
  The in-tree leg keeps shape, tamper and the inTree block, and a record that
  still carries `inTree.registryRecords` is RED as a retired layout. The
  watch hints drop ui/packages/** and the records directory. Self-test: the
  nine digest rows go with the code they tested; two rows pin the new
  boundary (the per-package record is RED; a run whose artefact did not move
  leaves the record as it was). Floor 29 -> 21.
- gen-sdui-manifest-node: no digests, no index refusal, no per-package
  records; it no longer imports the gate. The record note is rewritten.
- scripts/sdui-manifest.sources/ is deleted and the record regenerated
  (artefact byte-identical, sha256 1f6e1ccb925a).
- check-changeset-no-major, lint.yml, ci.yml and releases-maintenance.md
  stop naming the per-package records.
- AGENTS.md: the manifest paragraph still described the retired objectui
  pin (objectui:* scripts, "check-sdui-manifest reds until you do"). It now
  names the in-tree command and the CI step, line-neutral (5 lines).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS
Main re-recorded six registry packages under scripts/sdui-manifest.sources/
(#26274, #26358) while the manifest's bytes stayed the same: six
modify/delete conflicts against this PR's deletion of those records,
resolved by deleting them.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS
@github-actions github-actions Bot added size/l ci/cd documentation Improvements or additions to documentation labels Oct 27, 2026
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 27, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 27, 2026 00:48
@os-zhuang
os-zhuang enabled auto-merge October 27, 2026 00:58
#26277 re-recorded scripts/sdui-manifest.sources/plugin-detail.json while
the manifest's bytes stayed the same: one modify/delete conflict against
this PR's deletion of the records, resolved by deleting it.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit e931621 Oct 27, 2026
61 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-6qe56u branch October 27, 2026 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd documentation Improvements or additions to documentation size/l skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants