Skip to content

fix(sdui): the lockstep and manifest gates judge the in-tree ui/ copy when .objectui-sha is absent - #25833

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-6qe56u
Oct 25, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/project-thread-6qe56u

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

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 of lint.yml job lint-repo-tooling (the required Lint & Repo Gates lane) read that pin, and without it both exit 1. Measured on the sitting tree (cutover c326d2fdf1 + 4a 50bd417d30 with its README apply steps 2–3 + main b00fc55c7d) 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 on main as it is, so it can merge right after the cutover and before 4a, and main is 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-sha alone.

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:

  • lockstep: every judge() outcome over the existing fixtures;
  • manifest: checkTree over 14 fixtures × 2 option sets;
  • the real main output of both gates.

The existing self-test rows are unchanged and pass.

With no pin:

  • scripts/check-sdui-lockstep.mjs compares packages/sdui-parser/src with ui/packages/sdui-parser/src directly. It uses the same three readings the record holds today: the grammar region of parse.ts, the diagnostic code set, and the not-a-container containment predicate. The record is not consulted.
  • scripts/check-sdui-manifest.mjs:
    • Checks 1–2 (shape, tamper) are unchanged, held against the in-tree record fields.
    • Check 3 becomes a registry source digest. It is a sha256 over the src/ files (tests excluded) of the @object-ui/* workspace closure of @object-ui/core and 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.
    • A mismatch prints the one command that clears it: node scripts/gen-sdui-manifest-node.mjs.
    • There is no check 4. The in-tree @object-ui/core version 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:
    • It builds the registry closure itself with turbo (a cache hit when nothing moved), then enumerates from ui/apps/console exactly as before.
    • It refuses registry sources that the index does not hold.
    • It writes the record's inTree block and an in-tree // note.
  • Pin absent and ui/ absent: both gates exit 1, and the message names both .objectui-sha and 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.json and scripts/sdui-manifest.record.json are 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 pin b41ed7f689 and freeze 9e1fe03286:

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:

✗ check-sdui-manifest:
  record is missing `inTree`.
    The record is keyed to the one producer, which reads the in-tree console build (ui/apps/console). Regenerate:
    node scripts/gen-sdui-manifest-node.mjs

The registry source digest is identical on cutover c326d2fdf1 alone 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.mjs and 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's generatedAt date (the artefact itself is byte-deterministic).

Verification

Gate main (this branch) sitting tree + this PR
pnpm check:sdui-lockstep (self-test, then the gate) 0 (pin mode) 0 (in-tree: 214 grammar lines, blob 0131f27cf86d, 25 codes, predicate 76c18fb95d1f)
node scripts/check-sdui-manifest.mjs --self-test 0 (22 cases) 0 (22 cases)
node scripts/check-sdui-manifest.mjs 0 (pin mode, 107 components) 1 before 4a's regeneration, as above; 0 after it

Deviations from the order

  1. No regenerated artefact in this PR (dispatcher ruling, after the 106/107 measurement above). The order asked that the generator reproduce the committed sdui.manifest.json byte for byte on the sitting tree; it cannot, so the regeneration moves to 4a.
  2. No in-tree version judgment (accepted): objectuiWorkspaceVersion is provenance, printed beside the live ui/packages/core version.
  3. The generator builds the registry itself in-tree (accepted), so regeneration is one command with no prior step.

🤖 Generated with Claude Code

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
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 25, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 25, 2026 20:41
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 25, 2026 20:42
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 25, 2026
Merged via the queue into main with commit e2aaaf1 Oct 25, 2026
52 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-6qe56u branch October 25, 2026 20:58
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xl skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants