Skip to content

fix(sdui-manifest): one producer from objectui's built tree; retire the declaration-parity ratchet and the browser dump - #19921

Merged
os-zhuang merged 4 commits into
mainfrom
claude/issue-17735-sdui-manifest-one-producer
Sep 24, 2026
Merged

os-zhuang merged 4 commits into
mainfrom
claude/issue-17735-sdui-manifest-one-producer

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #17735
Clause-②: no

Executes maintainer ruling 丙 on #17735 (ruling record 5724940904, batch #151 item 2; verification record 5717306177; maintainer re-affirmation 5791879338 over ruling #197 A's PR #19270 path). The fence notes 5756239563 and 5786373289 are cleared: PR #19270 was closed unmerged by the re-affirmation, and the census in claim 5800589054 found every path clear. PR #18608 (squash 681ebe4246) already discharged the earlier ruling's item 4 (the check-generated.ts why string). This PR does steps 1–3 of 丙 and leaves step 4's list in place. The witness ledger is the one exception, shrunk by three rows (see Deviations).

⚠️ Governed surfaces: AGENTS.md and docs/adr/** (Tier H), plus .claude/hooks/** (Tier S, comments only). This PR stays draft and lands by the maintainer's hand.

Step 3 first: the byte comparison decided the shape of this PR

Both producers were run once over one built tree, .cache/objectui-62597c588072 (objectui at pin 62597c588072636e9c30ea35b3d89b1e46fd765d, built by pnpm objectui:build, VERDICT command-exit 0):

$ node scripts/gen-sdui-manifest-node.mjs            # the new built-tree producer (this PR)
✓ wrote sdui.manifest.json (59 components, 85726 bytes, sha256 22c83c9ec701…)
$ PLAYWRIGHT_BROWSERS_PATH=SCRATCH/pw bash scripts/gen-sdui-manifest.sh   # the browser dump, as on main
✓ wrote 59 public blocks → packages/console/dist/sdui.manifest.json
$ cmp packages/console/dist/sdui.manifest.json sdui.manifest.json; echo CMP_EXIT=$?
CMP_EXIT=0
$ sha256sum packages/console/dist/sdui.manifest.json sdui.manifest.json
22c83c9ec70163559c2bd8f7b1613174d8660ad9949d15ed483a4189b7857c9a  packages/console/dist/sdui.manifest.json
22c83c9ec70163559c2bd8f7b1613174d8660ad9949d15ed483a4189b7857c9a  sdui.manifest.json

The outputs are identical, so the ruling's copy branch applies. build-console.sh now copies the tracked sdui.manifest.json into packages/console/dist/. scripts/gen-sdui-manifest.sh, pnpm sdui:manifest and cut-rc's Playwright install step are retired. The dump ran against the container's chromium 1194, exposed under the revision name that playwright 1.62.1 asks for through a scratch PLAYWRIGHT_BROWSERS_PATH. Nothing was installed. The dump script's trailing ratchet did not run: it is guarded on the baseline file, which this branch had already deleted, and that guard sits after the dump wrote its file.

Step 1: M1 is the standing producer

  • scripts/gen-sdui-manifest-node.mjs takes no arguments.
    • It derives the modules root .cache/objectui-SHA12/apps/console from .objectui-sha.
    • It refuses to run, with pnpm objectui:build as the remedy, when the tree is missing, when the tree's HEAD is not the pin, or when the tree is not built (apps/console/node_modules/@object-ui/core/dist/index.js absent). It also refuses any argument, so the retired --objectui-version and --modules-root fail loudly instead of being ignored.
    • The temp-npm-install default is deleted.
    • The runner file is written to its own mkdtemp dir and removed afterwards. A resolve hook re-anchors bare specifiers to the modules root, so module resolution is unchanged and nothing lands in the build tree. Measured: 0 runner files in apps/console, 0 leftover temp dirs.
    • Output is deterministic: two runs, cmp identical.
  • scripts/sdui-manifest.record.json now records source: built-tree, modulesRoot and objectuiWorkspaceVersion (read from the built @object-ui/core/package.json), and its // block is rewritten.
  • scripts/check-sdui-manifest.mjs is re-keyed.
    • The presence check now requires source (it must equal built-tree), modulesRoot and objectuiWorkspaceVersion.
    • Check 4 compares objectuiWorkspaceVersion, and the header prose and every remedy line name pnpm objectui:build && node scripts/gen-sdui-manifest-node.mjs.
    • The self-test seed writes the new keys. One new row, a record from the retired npm-install route is RED, raises the floor to 12.
  • npm-route prose rewritten in: the generator header (the dead-citation fact of [finding] scripts/gen-sdui-manifest-node.mjs:28 still carries the dead objectui#6741 citation that PR #18608 removed from two sibling files — and it is the header both corrected sites point readers to #18627 is restated without a number), the record's // block, build-console.sh's trailing reminder, the AGENTS.md pin-move paragraph (located by content), docs/releases-maintenance.md (the "After the pin moves" section, the pin-policy step 4 and the rc-cut step 2), scripts/bump-objectui.sh (header, NEXT STEP text and the not-on-main warning) and the lint.yml comment on the check-sdui-manifest step.
  • Artefact regenerated at the pin: 57 → 59 components (box and object-tree added), 66,910 → 85,726 bytes, sha256 49211fee7792… → 22c83c9ec701….
    • 19 components differ in their input-name set: 38 names appear only in the new artefact and 3 only in the old.
    • dataSource is now on 15 components (it was on 0).
    • actionType replaces type on action:button and action:icon.
    • flex.isContainer is now true.
    • dashboard.refreshInterval became refreshIntervalSeconds.
    • The rest are object-kanban/object-calendar inputs, plus text.align and text.variant.

Step 2: the parity ratchet retires

Removed: packages/spec/scripts/check-react-blocks-declaration-parity.ts, its test, packages/spec/react-declaration-parity.baseline.json, the gate's only helper packages/spec/scripts/manifest-prescription.ts (the two deleted files were its only importers), the check:react-declaration-parity script, the lint.yml step, and the cut-rc steps Install a Playwright browser for the manifest dump and Declaration-parity ratchet at the committed pin (ADR-0082 D4).

ADR-0082 decision 4 gains exactly one status line: 「retired 2026-09-18 by maintainer ruling on #17735; the artefact stays for the CLI witness and the freshness gate」. That is an amendment, not a rewrite.

Knock-on edits:

  • check:generated's EXTERNAL_INPUT_REQUIRED bucket is now empty. The bucket and its reconciliation are kept, and the ledger test asserts 0 needing an external input.
  • published-projection-choke-point.test.ts loses the deleted file's allowance row.
  • gen-sdui-manifest.sh goes with its three tests (gen-sdui-manifest-cleanup, -collision and -write-target), which are also removed from vitest.repo-tests.json.
  • pnpm check:cross-package-test-inputs reported two dispositions after the deletion, and both are applied. It reported scripts/gen-sdui-manifest.sh as an unheld glob for create-objectstack, so it comes out of the declaration and turbo.json. It reported that check-generated-ledger.test.ts no longer reads outside its package, so it comes out of the spec repo-tests list.

Folded cards (ruling step 5)

#18627 (dead citation in the generator header), #18633 (releases-maintenance.md clause and the instruction that caused the version skew) and #18632 (the parity header's 「dumped from」 sentence) are folded here. All three are already closed as not planned, each with a pointer to this card, so there is nothing further to close. #18407 stays open, and it is not addressed here. #14490 re-measure reading: the regenerated artefact has actionType on action:button and action:icon, and neither block has an input named type. The artefact also contains object-tree now.

Changesets

  • skip-changeset is the ruling's route for the scripts and the ADR line.
  • Because step 3's copy landed, this PR adds .changeset/sdui-manifest-one-producer.md (@objectstack/console: patch).
  • Which labels to apply is the seat's call. I wrote none.

⚠️ Premise correction for the changeset. Ruling step 6 describes the dist as gaining 「a file it already shipped from the browser dump」. Measured, that is false. The published @objectstack/console 17.0.0, 17.3.0 and 17.4.0 tarballs contain 0 sdui.manifest.json (control: package/dist/index.html 1 each). pnpm run release re-runs build-console.sh, which recreates dist/ from scratch, so the RC cut's copy never reached a tarball. The changeset states that. It also states that the console's exports map (./package.json only) keeps the file unreachable through exports for now.

Deviations, and why

  1. packages/lint/src/sdui-jsx-baseline.json is shrunk by 3 rows, although the dispatch listed it as untouched. With the regenerated manifest, flex declares isContainer, so the 32 jsx-not-a-container warnings no longer fire. The witness test (unedited) fails with 「STALE ledger rows … delete these rows … in this same PR」. The rows were deleted, none was added, and no count was raised, which is the ledger's own shrink-only rule. The ruling's step 1 regeneration forces this.
  2. Comment-only edits outside the claimed file surface, made because the dispatch asked for no dangling reference:
    • .claude/hooks/guard-process-kill.sh and its selftest said pgrep -s teardown is "live in two tracked scripts", one of which this PR deletes.
    • scripts/pm/os-verify-lock.sh, scripts/publish-smoke.sh, scripts/check-sdui-lockstep.mjs, scripts/check-pnpm-filter-targets.mjs and scripts/pnpm-filter-targets.mjs (the FOREIGN_SCOPES reason string).
    • packages/spec/src/ui/react-blocks.ts (a line comment naming the deleted baseline).
    • docs/audits/2026-06-react-blocks-conformance.md (a retirement note above its run instructions).
  3. scripts/objectui-changeset-digest.mjs's self-test asserted that the bump prints pnpm sdui:manifest. It now asserts the bump prints node scripts/gen-sdui-manifest-node.mjs, pnpm objectui:build and NEXT STEP.

References kept on purpose (history, not pointers)

  • packages/spec/CHANGELOG.md (release-owned).
  • ADR-0082's body and addenda (amendment only).
  • docs/protocol-upgrade-guide.md, and the packages/spec/src narratives in component.zod.ts (×3), conversions/registry.ts, migrations/registry.ts and retired-keys/17.ui__RecordDetailsProps__layout.ts. These explain why a past gate stayed green.
  • docs/audits/... (dated record).
  • Past-tense comments in publish-smoke.sh, publish-smoke-port-collision.test.ts, scaffold-e2e-boot-probe.test.ts and lib/docs-import-surface.ts.
  • Fixture strings in scripts/check-agent-test-spelling.mjs and scripts/pm/ci-failure.mjs.

Acceptance notes

  • component.zod.ts still has one forward-looking sentence: the check:react-declaration-parity gate 「carries the spec↔objectui parity burden going forward」. It is TSDoc on published spec source, so it was left for the spec seat.
  • The witness test's title still says 「57-component public tier」. The test is unedited per the dispatch, and its assertion reads length > 0.

Local verification

All results below were taken on head b7d0b3693a, the final commit, after git rev-parse --short HEAD.

  • Gate union:
    • node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands derived 155 families.
    • All 155 were run, each with its exit code recorded before any pipe, and all 155 exited 0. That includes check:pm-dispatch-gates (1905 cases, run detached because it exceeds the foreground cap), plus check:dual-build-cjs-loads, check:lean-entry-closure and check:type-check-debt after a full turbo run build --filter='./packages/*' --filter='./packages/*/*' (72/72 tasks).
    • Reconciliation with --ran exited 0: 「155 derived, 155 run, 0 NOT-MEASURED, 0 UNRUN」.
    • NOT MEASURED, as the derivation prints them: the 10 workflow-valued families, the six CI jobs scheduled by these paths (Test Core, Temporal Conformance, Dogfood Regression Gate, Dogfood Verify CLI, Build Core, Console Pin Gate), and the workspace, examples and downstream type-check programs. These belong to CI.
  • Lint: eslint narrowed to the 12 changed lintable files, --no-inline-config --format json.
    • The JSON reports 12 files, 0 errors and 0 warnings.
    • This narrowing is safe because eslint.config.mjs enables no type-aware linting (no parserOptions.project), and nothing imports a deleted file. So no untouched file's verdict can move. The repo-wide pnpm lint belongs to CI.
  • Tests:
    • @objectstack/lint full vitest run: 108 files, 4121 tests passed.
    • spec targeted run (check-generated-ledger, published-projection-choke-point, publish-smoke-port-collision, publish-smoke-boot-failure): 4 files, 38 tests passed.
    • @objectstack/vitest-filter-preflight config-wiring-sweep.test.ts: 65 passed.
    • @objectstack/spec typecheck (src, scripts and test layer): exit 0.
    • Self-tests: bump-objectui.selftest.sh 20/20, guard-process-kill.selftest.sh 69/69, os-verify-lock.sh --self-test pass, check-sdui-manifest.mjs --self-test 12 cases.
  • Gate at the pin, with the objectui oracle: node scripts/check-sdui-manifest.mjs --require-objectui exit 0, reporting 「@object-ui 17.6.0 is the version objectui 62597c588072… declares」.
  • Ablation (one-shot, restored byte-exact by scripts/ablation-replace.mjs): with the re-key reverted to ['objectuiSha', 'sha256', 'components'], the self-test reds on exactly the new row (「a record from the retired npm-install route is RED — expected RED, got GREEN」, exit 1). The restore leaves the blob equal to HEAD b6484613ce99 and git diff HEAD empty.
  • Generator refusals, probed on a scratch copy (each exit 1, nothing written): an argument, no tree, a tree at the wrong HEAD, and a tree at the pin but not built.
  • build-console.sh's new block was exercised on fixtures: fresh (copied, ✓ line), stale record pin (copied, ⚠ with the regeneration step) and missing artefact (exit 1). A full pnpm objectui:build on this branch's first commit also passed; that run's ending came before the copy block existed.

维护者速读(草稿)

改了什么 —— sdui.manifest.json 只剩一个生产者:gen-sdui-manifest-node.mjs 直接读 pin 上已构建好的 objectui 树,不再从 npm 装旧包。声明对齐门禁(ADR-0082 D4)和浏览器 dump 一起退役。console 构建把这份受跟踪的 manifest 原样拷进 dist。

为什么改 —— 裁决 丙。实测两个生产者在同一棵已构建树上逐字节相同(cmp 退出码 0),所以浏览器那一路没有存在的必要。manifest 重新生成后,缺的 dataSource、actionType 等 38 个输入全部回来了。

风险与代价(含回滚) —— 以后升 pin 要先 pnpm objectui:build(约 10 分钟),再跑生成器。每个 PR 的门禁照旧离线,不变。console 包会第一次真的带上这个文件:此前发布的 17.0.0、17.3.0、17.4.0 都没有。但包的 exports 只导出 ./package.json,CLI 现在还读不到它,所以对用户没有行为变化。回滚就是 revert 这个 PR。

席位意见 ——

你要做的 —— 审阅后亲手合并(治理面:AGENTS.md、ADR)。


Generated by Claude Code

… unwired

Generator reads objectui's built tree at the pin; the npm-install default is
gone. check-sdui-manifest re-keyed to source/modulesRoot/objectuiWorkspaceVersion.
The react declaration-parity script entry and lint step are removed; the
check:generated EXTERNAL_INPUT_REQUIRED bucket is emptied.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr
…onsole ships the tracked manifest

The node generator's output over objectui's built tree at the pin and the
browser dump over the same tree are cmp-identical, so the dump retires:
build-console.sh copies the tracked sdui.manifest.json into the console dist.
The declaration-parity gate, its test, baseline and helper are deleted, with
the lint and cut-rc steps. The manifest is regenerated at the pin and the
JSX witness ledger drops its three rows that went stale with it.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 3 changed file(s) yielded no anchor (packages/lint/src/sdui-jsx-baseline.json, packages/spec/react-declaration-parity.baseline.json, packages/spec/vitest.repo-tests.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 2 changed package(s)).

What this run could not see
  • 3 changed file(s) yielded no anchor (packages/lint/src/sdui-jsx-baseline.json, packages/spec/react-declaration-parity.baseline.json, packages/spec/vitest.repo-tests.json) — pages documenting those are invisible to this run
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json beac7980267a361c5979ca7aa75c034624955af0 → packageMentionDocs.

@github-actions github-actions Bot added ci/cd dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation protocol:ui tests tooling labels Sep 23, 2026
This was referenced Sep 23, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 24, 2026 15:08
@os-zhuang
os-zhuang requested a review from hotlong as a code owner September 24, 2026 15:08
@os-zhuang
os-zhuang enabled auto-merge September 24, 2026 15:08
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 24, 2026
Merged via the queue into main with commit 28ce612 Sep 24, 2026
38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation protocol:ui size/xl tests tooling

Projects

None yet

2 participants