Repository navigation
fix(sdui): the lockstep and manifest gates judge the in-tree ui/ copy when .objectui-sha is absent - #25833
Merged
Conversation
…s absent Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS
…irections Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS
…stry when the pin is absent Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS
…tree producer Nine rows for the no-pin mode, each a real git fixture: the digest reds a staged registry source edit and a new workspace edge, ignores tests, unreached packages and unstaged bytes; no pin and no console reds naming both; a pin-mode record reds with the in-tree command; the in-tree producer builds through a stub turbo and writes a tree the gate passes. Git children over fixtures run with gitFreeEnv(); an in-tree record writes its own note. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS
This was referenced Oct 25, 2026
os-tesla
pushed a commit
that referenced
this pull request
Oct 25, 2026
main now carries ui/ (cutover #25825) and the dual-mode sdui gates (#25833). .changeset/config.json keeps this branch's side ("object-ui" in the fixed group, which the root PRIVATE_FIXED_MEMBERS rule accepts); scripts/ui-import/README.md (added on both sides) keeps the cutover's splice procedure first and 4a's record after it. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0149BHSXfCdQywGaLdpRAtWe
os-zhuang
pushed a commit
that referenced
this pull request
Oct 25, 2026
…s the fixed group, @objectstack/console builds from ui/apps/console, the objectui pin is deleted (#25711) (#25745) <!-- claude-projects-attribution: {"github_login":"os-tesla"} --> _Requested by **Tesla** · [project thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6JaoKAHLK79xmvJyPStopRpPQ2)_ Part of objectstack#25677 Fixes #25711 Blocked-by: sub-issue 5 of #25677 (the subtree PR that adds `ui/`; not filed yet) Clause-②: no Metadata-protocol: none **Maintainer rulings (Tesla, 2026-10-25 09:06Z, director thread):** 17a — the release npm token has publish rights on `@object-ui`. 17b, ruling B — the private VS Code extension `object-ui` stays in the one fixed group. 17c, ruling B — the QUICK_REFERENCE release-sync rows retire; decision B (17c) carried here. > ⛔ **Tier H, cutover sitting.** The cutover #25825 is on `main` (`fd40831416`, with #25833). This PR merged `main` and applies its `ui/` half as tree edits on that tree. Local verdict on `fb110c2323`: comment 6404553650, every step and gate exit 0. It merges per ruling 30 = B once that sweep is clean and the four fast lanes are green. > Body refreshed 2026-10-25T22:55Z on head `fb110c2323` (the merge of `main` `fd40831416` is `e2db258a24`). Comments read through 6404553650. ## What changes **1. One fixed group** (`.changeset/config.json`). The 38 public `@object-ui/*` packages and the private VS Code extension `object-ui` (17b) join the `@objectstack/*` fixed group; `@object-ui/example-*`, `@object-ui/site`, `@object-ui/runner` and `@object-ui/test-support` are ignored, as in objectui. (objectui#13506 made `@object-ui/runner` private before the freeze at `9e1fe03286`.) `ui/.changeset/config.json` is deleted by the ui-side patch (changesets reads one config per repository), and objectui's 65 pending `ui/.changeset/*.md` stay under `ui/` for aftercare #25831. Measured on cutover head `c04b36dcb9`, moving them as they stand reds `check-empty-changeset` (3 empty frontmatters) and `check-adr-0087-registration` (41 breaking changesets with no disposition). Root `check-changeset-fixed` accepts a private name in the group only when `PRIVATE_FIXED_MEMBERS` declares it (`object-ui` alone, with its reason), the package is private, and `privatePackages.version` is true; it reds if that member leaves the group. `check:lockstep-package-count` subtracts the declared private members, so the published count is 111. `check-changeset-no-major` now reads `packages/console/build-dist.sh` as the Console's packed-copy build script, and `check-empty-changeset`'s frontmatter-parser family loses the deleted objectui digest. **2. `@objectstack/console` builds in this workspace.** `packages/console/build-dist.sh` copies `ui/apps/console/dist` (built by turbo through `@object-ui/console#build`) into `packages/console/dist`, ships the tracked `sdui.manifest.json` (ADR-0080), and runs the single-zod canary over the bytes it ships. Root task `@objectstack/console#build:dist` (`turbo.json`) depends on `@object-ui/console#build`; `pnpm console:build` runs it, and `pnpm release` / `cut-rc.yml` run it after `pnpm run build`. `files` and `prepublishOnly` are unchanged. `scripts/build-console.sh` is deleted. The CLI's remedy for a missing Console dist names `pnpm console:build`. **3. The objectstack-side pin is deleted.** `.objectui-sha`, `scripts/bump-objectui.sh` (+ selftest), `scripts/objectui-changeset-digest.mjs`, `scripts/objectui-range.mjs`, `scripts/check-prerelease-pin-watch.mjs`, `scripts/check-console-sha.mjs`, `scripts/check-console-injection.mjs`, `scripts/assert-console-spec-injection.mjs`, `scripts/console-spec-probes.mjs`, `packages/spec/scripts/build-console-objectstack-root.test.ts`; the pin reads in `cut-rc.yml` ("THE objectui PIN IS AN INPUT HERE" and `Read the committed objectui pin`), `release.yml`, `lint.yml`, `showcase-smoke.yml` and the root `package.json` scripts (`objectui:*`, `check:console-sha`, `check:console-injection`, `check:objectui-*`, `check:prerelease-pins`; `pnpm dev*` no longer runs `check:console-sha`). `scripts/check-console-intercept-disarm.mjs` stays. Release notes (`collect-release-notes.sh`) say "no objectui pin" when the new ref has none. Gate self-tests and rosters that named the deleted scripts follow (`dispatch-gates`, `pnpm-filter-targets`, `check-pnpm-filter-targets` (tree-aware: foreign `@object-ui/` targets must be 0 without `ui/`, >0 with it), `bare-root-worklist`, `check-type-check-coverage`). The lockstep count in `content/docs/protocol/backward-compatibility.mdx` and `scripts/publish-smoke-pack.mjs` reads 112, both scopes (`check:lockstep-package-count --fix`), and `packages/spec/vitest.repo-tests.json` drops the deleted test. **4. The objectui-side pin is deleted, in `ui/`.** Until `ui/` was on `main`, this half was carried as `scripts/ui-import/4a-ui-side.patch`. After the cutover landed, `fb110c2323` applied it under `ui/` with README step 2's deletions, then deleted the patch file. `scripts/ui-import/README.md` now records what was applied. It deletes `.objectstack-sha`, `.objectstack-pin/`, `bump-objectstack.sh`, `objectstack-pin.mjs`, `objectstack-floor.mjs`, `check-spec-range-floors.mjs`, `check-installed-spec-pin-claims.mjs`, the dist-pin Vite probes `vite-objectstack-spec-dist.ts` / `vite-objectstack-client-dist.ts`, `changeset-release.yml`, `spec-range-floors.yml`, `release-github-releases.mjs` and their tests, plus (17c) `sync-quick-reference-release.mjs`, its test and the `quick-reference-current-release-4143` pin, with `QUICK_REFERENCE.md`'s version rows. The single-zod guard moves to `ui/scripts/vite-single-zod.ts` (it runs in every console build); `apps/console/vite.config.ts` drops both injections. Every reader of the Changesets config goes through a new `changesetConfigPath()` (own root standalone, monorepo root when nested); objectui's `check-changeset-fixed` and `check-unused-dependencies` otherwise keep their extension rules (17b). The patch was written against verify head `9e37acd126` and checked with `git apply --check` on cutover heads `1c0d02eda4` and `c04b36dcb9` and on `main` at `fd40831416`. It also deletes the nested `ui/.github/pull_request_template.md`, which never renders and whose only markdown-test-inputs reader was the claims test. **6. SDUI manifest.** Carries the sdui manifest regeneration for the merged tree (107 → 106 components; objectui#13449 retired html): `sdui.manifest.json` and `scripts/sdui-manifest.record.json`, regenerated from `ui/` now that `.objectui-sha` is gone and the dual-mode gates (#25833) read the in-tree oracle. **5. One release lane.** objectui's `changeset-release.yml` is gone; root `release.yml` publishes both scopes in one `pnpm -r publish`, and the root `scripts/release-github-releases.mjs` cuts one GitHub Release per package tag across both scopes. ## The four deleted Console checks, and what proves the same thing now | Deleted | What it proved | Now | |---|---|---| | `assert-console-spec-injection.mjs` | the built Console bundles THIS tree's `@objectstack/spec`, not the copy objectui's lockfile installed | Can no longer be false. Every `@objectstack/*` dependency under `ui/` is `workspace:^` (33 spec, 2 client, 2 lint, 2 formula rows measured), which pnpm links and never resolves from the registry; the merged lockfile has 0 registry entries for `@objectstack/spec` or `@objectstack/client` and 37 `link:` rows to `packages/spec`. The single-zod guard (Vite, `ui/scripts/vite-single-zod.ts`) and canary (`build-dist.sh`, on the shipped bytes) still run in every build. | | `check-console-injection.mjs` | a Console dist restored from the pin-keyed cache was built against the current spec | Can no longer be false. The cache keyed on `.objectui-sha` is gone; turbo's hash for `@object-ui/console#build` includes `@objectstack/spec#build`, `@objectstack/client#build` and `@objectstack/lint#build` (measured with `turbo run build:dist --filter=@objectstack/console --dry=json`), so a spec change misses the cache. | | `check-console-sha.mjs` | the local `packages/console/dist` was built from the pinned objectui commit | The pin it compared against is gone, so that drift cannot occur. A local dist can still be older than `ui/` after a pull; `pnpm console:build` rebuilds it (a turbo cache hit when nothing changed). Nothing checks this on `pnpm dev` any more: reported to the dispatcher. | | `console-spec-probes.mjs` | the shared probe derivation for the two injection checks above | Left with them; nothing else imported it. | ## Verification (merged tree at objectui@cd70b7818; the 17b/17c items re-measured on verify head `9e37acd126`) - `pnpm changeset version` on the cutover head `1c0d02eda4` (objectstack#25825, objectui frozen at `9e1fe03286`) + this PR + the ui patch: exit 0, and all 112 members move 18.1.0 → 18.2.0 together (111 public: 73 `@objectstack/*` and 38 `@object-ui/*`, plus `object-ui`). The private, ignored `@object-ui/runner` stays at 18.1.0. On that tree root and objectui `check-changeset-fixed` and `check:lockstep-package-count` exit 0. - Earlier, on verify head `9e37acd126` (when `@object-ui/runner` was still public): all 113 members move 18.1.0 → 18.2.0 in one bump: 112 public (73 `@objectstack/*`, 39 `@object-ui/*`) and the private extension `object-ui`. The other private `@objectstack/*` packages move as they do on `main`. `pnpm -r publish` and `release-verify-npm` skip `object-ui` (private), so nothing it owes the registry changes. - `pnpm -r publish --dry-run` after the version (at `9e37acd126`): 112 packages, 39 `@object-ui/*` + 72 `@objectstack/*` + `create-objectstack`, all 18.2.0. `pnpm pack` of `@object-ui/core`: `@objectstack/spec` `workspace:^` → `^18.2.0`, `@object-ui/types` `workspace:*` → `18.2.0`. - `pnpm console:build` (CI=true): exit 0, single-zod canary green. The packed `@objectstack/console` has the same top-level `dist/` entries as the published 18.1.0 tarball, minus `dist/.objectstack-injection.json` and `dist/.objectui-sha`; assets 2,268 → 2,381 (newer objectui), tarball 9,260K → 9,140K. - Console eager-closure budget (`ui/scripts/check-eager-closure-budget.mjs`, ceiling 3,496.0 KB): this build 3,054.2 KB gzipped, `vendor-objectstack` 1,605.2 KB; the published 18.1.0 dist measured by the same ceilings: 3,522.3 KB, `vendor-objectstack` 1,851.5 KB. The membership half is red identically on both (`packages/core`: 1 of 89 modules in `vendor-objectstack`), so it predates this PR. - The ui-side patch on verify head `9e37acd126`: `git apply --check` passes after README steps 1–2 and reproduces the edited `ui/` tree byte for byte (60 files). With this PR's root half, install and `pnpm run build`: `type-check:scripts`, `type-check:vitest-config`, `lint:root` exit 0; root and objectui `check-changeset-fixed` pass; `vitest run scripts/__tests__` 17 failed / 5,573 passed, where 2 are 15 s load timeouts that pass alone, 2 fail the same way without the patch (`check-lockfile-integrity`; `quick-reference-commands-4149` on the root scripts the adaptation drops, cutover bill), and 14 read objectui's nested `ui/.github/`, which 4b PR 2 deletes. - actionlint 1.7.7 over `release.yml`, `cut-rc.yml`, `lint.yml`, `showcase-smoke.yml`: exit 0. No step reads a pin file. ## Gates (this branch, no `ui/`) `dispatch-gates --commands` derives 166 families for this diff; all 166 ran, and `dispatch-gates --ran` reconciles: 164 run, 2 NOT-MEASURED. All were run on head `4ac569dc00` (after merging `main` at `f0cf338330`, which had moved `.objectui-sha` and the root `build` script), after a full `pnpm run build`. 156 exit 0, including `check:required-contexts`, `check:workflow-status-functions`, `check:workflow-step-name-quoting`, `check-changeset-no-major`, `check-empty-changeset`, `check-adr-0087-registration`, `check:lockstep-package-count` (112) and `check:nul-bytes`. One is red on `main` itself and not this PR's: `check:liveness` (`translation/flows.screens` cites `service-automation/src/engine.ts`, which #25734 refactored; this PR touches neither). The other 9 are red or not measured because `ui/`, PR B or 4b has not landed yet, as designed: | Gate | Exit | Why red here | Clears when | |---|---|---|---| | `check-changeset-fixed` | 1 | the 38 `@object-ui/*` names and `object-ui` in `fixed` have no package without `ui/` (on cutover head `1c0d02eda4` + this PR + the ui patch: exit 0, 111 public + 1 declared private) | sub-issue 5 | | `check-prerelease-pin-watch --self-test`, `--verbose` | 1, 1 | named only by `prerelease-pin-watch.yml`; this PR deletes the script | PR B of #25697 | | `check-self-test-wired --self-test` | 1 | `ci.yml` `console-pin` and `prerelease-pin-watch.yml` still invoke deleted scripts | PR B of #25697 | | `check:pm-dispatch-gates` | 1 | 3 of 1,913 fast-tier cases, all on the same live invocations of deleted scripts | PR B of #25697 | | `check:console-sha`, `check:console-injection` | NOT-MEASURED (254) | root scripts deleted here; only the `console-pin` job names them | PR B of #25697 | | `check-sdui-manifest`, `check:sdui-lockstep` | 1, 1 | they read `.objectui-sha` | 4b PR 2 (#25712) | ## Depends on, outside this PR - **Sub-issue 5** (subtree PR): adds `ui/`; this PR merges right after it. - **PR B of #25697** (retire the pin gates in the cutover window): removes the `console-pin` job and `console` filter in `ci.yml`, `prerelease-pin-watch.yml`, and the live specimens in the `dispatch-gates` self-test that still name `check-prerelease-pin-watch.mjs`. Until it lands, `prerelease-pin-watch.yml` runs a script this PR deletes. - **4b PR 2 (#25712)**: `check-sdui-lockstep`, `check-sdui-manifest` and `gen-sdui-manifest-node` read `.objectui-sha` and go red without it; regenerating `sdui.manifest.json` from `ui/` is theirs (the root copy lags the old pin, and `build-dist.sh` ships the tracked one). Also the nested `ui/.github/` and the tests that read it, and both AGENTS.md files. - **Maintainer**: the npm token's `@object-ui` publish rights (card risk 1) — confirmed by Tesla, ruling 17a. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_0149BHSXfCdQywGaLdpRAtWe --------- Co-authored-by: Claude <noreply@anthropic.com>
os-zhuang
pushed a commit
that referenced
this pull request
Oct 26, 2026
…ws (#25834) <!-- claude-projects-attribution: {"github_login":"os-tesla"} --> _Requested by **Tesla** · [project thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoAqVfFyhsxKuFcEP9YTBj25)_ Part of #25712 (4b PR 2b: the governed register learns the `ui/` workspace). Part of objectstack#25677. Clause-②: no Metadata-protocol: none ## 维护者速读(草稿) - **改了什么:** 受管面登记表新增 `ui/` 工作区的六行(`ui/docs/adr/**`、`ui/.claude/**`、`ui/skills/**`、`ui/AGENTS.md`、`ui/CLAUDE.md`、`ui/.github/workflows/**`),全部 Tier H,只管 objectstack;CODEOWNERS 同加六行;`AGENTS.md` 第 14 条与 pm-dispatch 技能的路径分叉段写上这六个面。 - **为什么改:** objectui 合进 `ui/` 之后,它原来自己的受管面不能落空;第 16 项裁决(`ui/.claude/**` 在并入根 `.claude/**` 之前保持 Tier H)。 - **风险与代价(含回滚):** 两个指令文件都在行数上限,本 PR 不加行、不抬上限,靠原地压缩措辞付账;回滚 = revert 本 PR。`main` 上还没有 `ui/`,这六行在 cutover 之前不命中任何路径。 - **席位意见:**(留空) - **你要做的:** 批准本 PR(Tier H,因为改了 `AGENTS.md`)。 ## What changes - `scripts/pm/check-governed-merges.mjs`: six rows on `GOVERNED_SURFACES`. They are objectui's own register (every root row except the North Star) prefixed with `ui/`, scoped `repos: ['objectstack']`, and all Tier H. `ui/.claude/**` is included, because it stays Tier H until it folds into the root `.claude/**` (Tesla, 2026-10-25, director item 16). - The self-test's `UI_SPECIMENS` rows from PR 1 (#25732) now pin the live rows. The flipped pin is `today-the-register-does-not-know-ui-…`, which becomes `the-register-knows-ui-the-rows-are-live`. - The register seam stays covered by the one register that does not carry the rows. - The counts that read the register move from 7 to 13 for objectstack only. cloud and objectui stay at 7, objectos and hotcrm at 6. - `scripts/pm/check-governed-queue-guard.mjs`: the CODEOWNERS mirror pins move to the live rows. With the `/ui/` lines removed, the file on disk is short exactly one line per row. The "13 surfaces govern objectstack" head is pinned. - `.github/CODEOWNERS`: six `/ui/…` lines routed to every `GOVERNED_APPROVERS` account. - `AGENTS.md` Prime Directive #14 and `.claude/skills/pm-dispatch/SKILL.md` (the ACCEPT path fork) name the six globs, as `check:pm-governed-prose` requires. - Both files are at their ceiling (1117/1117 and 319/319 lines). No ceiling was raised; both stay at those line counts, every line at most 120 bytes. - In AGENTS.md the paragraph is re-wrapped over its own ten lines. To make room, four clauses come out, quoted as they stood: 1. ` — this file is one —` after `` `CLAUDE.md` `` (`AGENTS.md` is already in the list). 2. `; a mixed diff is governed whole on one path hit.` (the next paragraph says it again). 3. `When it reds, name the surface here.` (the gate's own message says it). 4. `the` and `table` around `` `GOVERNED_SURFACES` ``: "The register is the `GOVERNED_SURFACES` table in" now reads "The register is `GOVERNED_SURFACES` in". - In SKILL.md, one line is paid by joining the install-surface probe line onto the cross-repo unblock criterion two lines above it, which leaves that line's quoted wording intact. ## Verification | Gate | `main` + this PR | sitting tree + PR 2a + this PR | |---|---|---| | `pnpm check:pm-governed-merges` (534 assertions) | 0 | 0 | | `node scripts/pm/check-governed-queue-guard.mjs --self-test` (345 cases) | 0 | 0 | | `pnpm check:pm-governed-prose` (13 surfaces, both regions) | 0 | 0 | | `pnpm check:pm-skill-ratchet` (AGENTS.md 1117/1117, SKILL.md 319/319) | 0 | 0 | - Derived gates (`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`): 54 families, all exit 0 at this head on `main` `e2aaaf1c07` (after PR 2a #25833). `--ran` reconciles 54 run, 0 NOT-MEASURED, 0 UNRUN. `check:doc-formula-expressions` needs `@objectstack/lint` built first. - `node scripts/pm/dispatch-gates.mjs --self-test` (both tiers, run by hand because CI runs the slow tier only on push and schedule): 0, 2182 cases (fast 1917 in 291 s, slow 265 in 875 s), measured on `b00fc55c7d` + this change; the one commit between that and this base is PR 2a, whose three files this PR does not touch. - On `main` the six rows are inert, because no `ui/` path exists there yet. - On the sitting tree (cutover `c326d2fdf1` + 4a `50bd417d30` + `main` + PR 2a), `node scripts/pm/check-governed-merges.mjs --test`: - exits 3 (governed, landing tier H) for `ui/.claude/x`, `ui/AGENTS.md`, `ui/CLAUDE.md`, `ui/docs/adr/0001-x.md`, `ui/skills/objectui/SKILL.md` and `ui/.github/workflows/ci.yml`; - exits 0 (0 of 1 path governed) for `ui/packages/x/src/y.ts`. - On the sitting tree, `check:pm-governed-merges`, the queue-guard self-test, `check:pm-governed-prose` and `check:pm-skill-ratchet` all exit 0. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Oct 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Tesla · project thread
Part of #25712 (4b PR 2a: the two SDUI gates keep the required lane green when the pin goes).
Part of objectstack#25677.
Clause-②: no
Metadata-protocol: none
Why
The sitting merges the cutover PR #25825 (adds
ui/), and then 4a #25745 (deletes.objectui-sha). Two steps oflint.ymljoblint-repo-tooling(the required Lint & Repo Gates lane) read that pin, and without it both exit 1. Measured on the sitting tree (cutoverc326d2fdf1+ 4a50bd417d30with its README apply steps 2–3 +mainb00fc55c7d) without this PR:pnpm check:sdui-lockstep:REFUSED — .objectui-sha could not be read, exit 1.node scripts/check-sdui-manifest.mjs:✗ .objectui-sha is MISSING — cannot judge freshness., exit 1.This PR gives each gate, and the manifest generator, a second oracle: the in-tree copy under
ui/. It is green onmainas it is, so it can merge right after the cutover and before 4a, andmainis never red. It deletes nothing:packages/sdui-parser/objectui-lockstep.json, the pin and every check stay. Unifying the two parsers is a later PR.What changes
The mode is decided by
.objectui-shaalone.With the pin (today's
main): zero behaviour change. The same record, checks, messages and output. Proven by golden harnesses, captured before and after and compared byte for byte:judge()outcome over the existing fixtures;checkTreeover 14 fixtures × 2 option sets;mainoutput of both gates.The existing self-test rows are unchanged and pass.
With no pin:
scripts/check-sdui-lockstep.mjscomparespackages/sdui-parser/srcwithui/packages/sdui-parser/srcdirectly. It uses the same three readings the record holds today: the grammar region ofparse.ts, the diagnostic code set, and thenot-a-containercontainment predicate. The record is not consulted.scripts/check-sdui-manifest.mjs:src/files (tests excluded) of the@object-ui/*workspace closure of@object-ui/coreand the generator's 16 registry modules. It is read from the git index (git ls-files -s: sorted paths, committed blob ids, no generated or untracked files), so the lint lane builds nothing.node scripts/gen-sdui-manifest-node.mjs.@object-ui/coreversion moves with every release of the fixed group while the registry does not, so it is recorded and printed as provenance only.scripts/gen-sdui-manifest-node.mjs, with no pin:ui/apps/consoleexactly as before.inTreeblock and an in-tree//note.ui/absent: both gates exit 1, and the message names both.objectui-shaand the in-tree path.Record fields added, and what stays untouched
The new block is
inTree: { modulesRoot, objectuiWorkspaceVersion, registryPackages, registrySources, registrySourcesSha256 }. It is written only by an in-tree run.The pin-mode fields (
objectuiSha,source,modulesRoot,objectuiWorkspaceVersion,generator,generatedAt,sha256,components) are untouched. An in-tree run carries the pin-keyed ones only while the artefact stays byte-identical to the one they describe.This PR commits no regenerated artefact.
sdui.manifest.jsonandscripts/sdui-manifest.record.jsonare unchanged, per the dispatcher's ruling below.The committed manifest describes the pin, not the frozen registry (measured)
On the sitting tree, the in-tree generator exits 0 and writes 106 components (
1f6e1ccb925a…). The committed artefact has 107 (d1fde278ffd6…). The registry really moved between pinb41ed7f689and freeze9e1fe03286:htmlnode type.deadmisreads as deletable (manifest.runtimecase) #13483, objectui#13386) reworded plugin-detail'ssectionsinput description.One committed artefact cannot be true for both the pin and the in-tree registry. So the regeneration rides with the pin deletion, in 4a: a ready patch and its measurements are with the dispatcher. Until 4a applies it, 4a's lint lane reds with exactly this:
The registry source digest is identical on cutover
c326d2fdf1alone and on the sitting tree: 27 packages, 922 files,35ef1abd88b0011a06bfc895b3091d1f8ecf319c3f78d2bfb0d9feb4e53f3bbe. So the regenerated record holds through both states. Two generator runs on the sitting tree were byte-identical, artefact and record.Known cost
After 4a, a UI PR that touches a registry source reds Lint & Repo Gates until its author runs
node scripts/gen-sdui-manifest-node.mjsand commits the two files. Measured: 96 of objectui's last 200 non-merge commits (2026-10-20..25) touched the digested set, so about half of UI PRs would pay that one command.The follow-up that removes the tax is a regenerate-and-compare step in Build & E2E UI (
ci.yml), which has the console build in hand. It is the next 4b dispatch. That compare must ignore the record'sgeneratedAtdate (the artefact itself is byte-deterministic).Verification
main(this branch)pnpm check:sdui-lockstep(self-test, then the gate)0131f27cf86d, 25 codes, predicate76c18fb95d1f)node scripts/check-sdui-manifest.mjs --self-testnode scripts/check-sdui-manifest.mjsThe in-tree oracle (no pin: the merged layout), 18 cases;inTreefrom the required list; the row stays red because the field-level check catches the same thing.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack): 35 families, all exit 0 at heada6ee32ec;--ranreconciles 35 run, 0 NOT-MEASURED, 0 UNRUN. ESLint on the three changed files: 0.gitFreeEnv()([finding] 25 more throwaway-git-repo builders spawngitwith no environment of their own — the #16624 class, enumerated, with three competing spellings of the fix in tree #16644).Deviations from the order
sdui.manifest.jsonbyte for byte on the sitting tree; it cannot, so the regeneration moves to 4a.objectuiWorkspaceVersionis provenance, printed beside the liveui/packages/coreversion.🤖 Generated with Claude Code
https://claude.ai/code/session_01A6SEitNngAMugGbuJHWsDS