Skip to content
This repository was archived by the owner on Oct 26, 2026. It is now read-only.

Commit 6f3299f

Browse files
objectstack-fleet[bot]claudeos-zhuang
authored
release(v18): objectui's first 18.x release — the sync major, Changesets pre mode on next, and the two gate edits (objectui#12334) (#12401)
Fixes #12334 Clause-②: no objectui's first 18.x release, prepared in one PR: the sync `major` that follows `@objectstack/*` from 17 to 18, Changesets pre mode on the `next` tag, and the two gate edits. Nothing is published by this PR. Publishing stays the maintainer's act (merging the version PR); `changeset version` and `publish-plan` ran only on a scratch clone and nothing they wrote is committed. ## What changes 1. **The sync major.** `.changeset/12334-objectstack-18-sync-major.md` declares `major` for all 40 members of the `fixed` group, so every package's CHANGELOG says why it crossed to 18. Its body is published text; for what a consumer must do it points at the `@objectstack/*` 18 entry of objectui#12030. 2. **Pre mode on `next`.** `.changeset/pre.json`, written by `pnpm changeset pre enter next`: `{ "mode": "pre", "tag": "next" }`. 3. **`scripts/check-changeset-no-major.mjs`, under the maintainer's ruling on objectui#12030 (comment 6149296149).** A `major` entry passes only when its package is in a `fixed` group AND that group's current major (the `version` its members declare, one major for all) plus one equals the major of the `@objectstack/spec` range its members declare in `dependencies` / `peerDependencies` / `optionalDependencies` (one major for all). Every other `major` is refused, with the reason printed per entry. The range reader is narrow (`^`, `~`, `=` or a bare `X.Y.Z`, prerelease allowed): a union, an open lower bound, an x-range or a protocol spelling refuses the `major` instead of guessing one, and so do members that disagree, a missing manifest, and a group none of whose members declares the spec. Manifests are read only when a `major` is pending. `OBJECTUI_ALLOW_MAJOR` is retired: the script reads no environment, pinned by a test on its comment-masked source. No workflow file changes. 4. **`scripts/check-spec-range-floors.mjs` reads a prerelease floor.** A lower bound may name a prerelease, and that exact prerelease is the floor: fetched from the registry and judged by its own export surface, like a release floor. No ordering is added: two different prerelease floors in one manifest, a `||` union with a prerelease branch, and the replacement-floor search (now `replacementFloorLine`, extracted from `main` so it is testable) still refuse or name nothing, and an unrecognised spelling still throws. 5. **Prose.** In `AGENTS.md` and `content/docs/guide/ci-cd-pipeline.md`, only the sentence that named `OBJECTUI_ALLOW_MAJOR` changes; each now states the computed admission and points at the script header as the authoritative statement. Six pending changesets get a one-clause correction (below). ## The `.changeset/pre/` question, measured Changesets 3 (installed `@changesets/cli` 3.0.1) keeps no consumed ids in `pre.json`. `enterPre` (`@changesets/pre`) writes `mode` and `tag` only. In pre mode, `changeset version` MOVES each consumed changeset to `.changeset/pre/` (`@changesets/apply-release-plan`). The planner leaves `pre/` out while `mode` is `pre` (`getRelevantChangesets` in `@changesets/assemble-release-plan`) and reads it again only on `pre exit`. So the bump gate reads top-level `.changeset/*.md` only. It always did; this PR states why in the header and pins it: - **It does not trip on a consumed `major`.** After the first prerelease the group is on `18.0.0-next.0`, whose major is already the spec's, so reading `pre/` would refuse the consumed sync major. - **It does not miss a pending one.** A new `major` lands at the top level and is refused, because 18 + 1 is not 18. That is "every other `major` is refused". - **On `pre exit`** the planner reads `pre/` again, but it increments the group's prerelease. A pre-major `X.0.0-TAG.N` increments to `X.0.0` for every bump type, so a consumed `major` cannot move the group off 18. Measured on a scratch clone of `bd8892e70`: - `pnpm changeset:version` printed `Version: 17.7.0 → 18.0.0-next.0`. All 40 group manifests went to `18.0.0-next.0`, 471 of the 471 pending changesets moved to `.changeset/pre/` (0 left at the top level), and `pre.json` was unchanged. - On that tree the bump gate exited 0 ("No changeset declares a `major` bump."). With one probe `major` added at the top level it exited 1: "carries the group from 18 to 19, but its @objectstack/spec range names 18". - `changeset publish-plan --output`: 39 entries, every one `publish` at `18.0.0-next.0` on tag `next`. The 40th member, `object-ui`, is private. - The release lane's post-version validation on that tree: `quick-reference:check` exit 0 and `check:control-bytes` exit 0. `vitest run scripts/__tests__`: 184 files passed and 3 failed. Two of the failures, `check-lint-rule-coverage` and `turbo-lint-inputs`, come from the scratch clone itself: its `node_modules` is a symlink, and `git check-ignore` refuses a path "beyond a symbolic link". Both pass in the real worktree. The third, `markdown-test-inputs` `stale-test`, was this branch's own: the rewritten bump-gate test read `.changeset/` only through the gate, which the scanner cannot see. `3cbf4dbb6` fixes it, and the ledger needed no edit. - Not exercised: the `Changeset Release` workflow itself. Its publish lane on a pre-mode tree is read from its clear step, which already removes `.changeset/pre/*.md` and keeps `pre.json`. It is not measured. ## The dispatch's mechanism assumptions, measured on `main` at `28fb2a0` - **A1 holds.** Every `@objectstack/spec` range in the workspace is `^18.0.0-next.1`. The fixed group is 40 members, all at `17.7.0`, and 22 of them declare the spec in a consumer-facing field. - **A2: both readings are right, at different layers.** `minVersionOf` throws on every range. `effectiveFloor` turns each throw into an `unreadable-range` finding, and no package counts as floored. `main()` then stops at the collapse alarm before printing any finding. `pnpm check:spec-floors` exited 1 with "The scan collapsed: 0 package(s) declare @objectstack/spec in a consumer-facing field, fewer than the 8 this repository has." - **A3 holds.** On `main` there is no `.changeset/pre.json` and no `.changeset/pre/`. `node scripts/check-changeset-no-major.mjs` exited 0 with "No changeset declares a `major` bump." - **A4 holds.** `git grep OBJECTUI_ALLOW_MAJOR` finds it in the script, `AGENTS.md` and the CI/CD guide, and nowhere under `.github/`. Control: the same grep for `check-changeset-no-major` finds 4 lines in `.github/workflows/changeset-guard.yml`. - **A5: carried by objectui#11824** (PR #12355, `cfb2947`). That PR rewrote the `{record.FIELD}` spelling in `.changeset/11788-notify-recipients-picker.md` as the CEL value envelope. Re-read at this head, "These are the values the messaging service already resolves" holds: the notify node evaluates an envelope recipient per run (`resolveRecipients` in objectstack `notify-node.ts`) and hands the messaging service the resolved values. Left unchanged. ## Pending changesets re-read (6159211733) The six corrections below each add one clause. Every frontmatter is byte-identical: `check-changeset-overwrite` reports "declared at base" equal to "declares now" for all six. - **`.changeset/11880-grid-filter-handoff.md`, the page-1 bullet.** This is the item the review named. "It now returns to page 1" now says that in 18 this holds for a named view's filter only, because `ObjectView` no longer reads `table.defaultFilters` (objectui#12030). - **The general check found four more.** The grep was by symbol and by the words that spell it, not by file path. Three retirements had landed after objectui#12030's sweep, and one more was a flow-template spelling: - `.changeset/11838-rename-expression-refs.md`: "a record field reads `{x.field}`". In 18 that value is a CEL value envelope, because spec 18 refuses the single-brace token there (objectui#12101). This is the flow-template class the review found. - `.changeset/11880-repeater-datasource.md` and `.changeset/12085-element-binding-inputs.md`: both still said the repeater reads its flat `properties.object` / `filter` / `sort` / `limit` as a fallback. objectui#12345 (PR #12366) removed that read today and left these two unchanged. - `.changeset/11865-access-panels-shared-select.md` and `.changeset/11865-object-settings-shared-select.md`: both still named the external sharing-model picker. objectui#12353 removed it today. These two spell it "external sharing model" in words, so a grep for `externalSharingModel` alone misses them. - **Read and left as written:** - `.changeset/12032-approval-requests-data-source.md`: "a record page over a `provider: 'api'` source". This is historical wording about `ApiDataSource`, the same reading objectui#12364's PR recorded. - The `defaultFilters`, `manage_org_presentation`, `*_OBJECT_REQUIRED`, `element:record_picker`, `actionType: 'navigation'` and `onSuccess` hits: each is already corrected, is its own retirement entry, or describes something that still holds. - **This list is valid at this head only.** Changesets that land before this PR goes ready need the same re-read. ## Acceptance, mapped | Acceptance | Result | |:--|:--| | This PR's changeset passes the bump gate | exit 0, "`.changeset/12334-objectstack-18-sync-major.md`: 17 → 18, 40 `major` entries" | | `pnpm check:spec-floors` reads every floor at `18.0.0-next.N`, exit 0 on a built workspace | exit 0; 22 of 39 published packages floored; 11 entry points of `@objectstack/spec@18.0.0-next.1`; `--cross-check` agrees | | `changeset version` + `publish-plan` on a scratch copy plan every package at `18.0.0-next.N` on `next` | 39 of 39 `publish`, `18.0.0-next.0`, tag `next` | | A `major` when the group already equals the spec's major is refused | fixture, and live on the post-version tree (18 to 19) | | A `major` two above the group's major is refused | fixture (group 16, spec 18) | | An unreadable range still fails the floor gate | fixtures, plus a live leg below | | `.changeset/pre/` measured, the gate neither misses a pending `major` nor trips on a consumed one | section above; pinned by two fixture tests and a live-tree enumeration test | | One ablation leg | below | | Nightly `Spec Range Floors` alarm green on `main` after landing | not measurable before merge | ## Verification at `3cbf4dbb6` - **Tests.** `pnpm exec vitest run` on `check-changeset-no-major`, `check-spec-range-floors`, `markdown-test-inputs`, `ci-cd-pipeline-doc`, `check-pre-install-import-graph` and `check-changeset-presence`: 6 files, 268 tests passed, exit 0. `pnpm type-check:scripts` exit 0, and `tsc --listFilesOnly` lists both test files. `eslint` on the four changed scripts: exit 0. - **Gates, run locally, all exit 0:** - `check-changeset-no-major`, `check-changeset-overwrite` (report-only, six "declared at base = declares now"), `check-changeset-fixed`, `check-changeset-presence` ("no changeset is owed") and `check-changeset-claims`; - `check-pending-changeset-literals`, `check-control-bytes`, and `check-pre-install-import-graph` (plus its `--self-test`); - `check-new-cross-file-line-citations` (0 new), `check-doc-links`, `check-doc-fence-languages`, `check-shell-escape-residue` and `check-entry-guard`. - **`pnpm check:spec-floors -- --cross-check`** exited 0 after `turbo run build` of the 22 floored packages and their dependencies (33 tasks). - **Ablation, three legs, each restored by a trap and checked by blob hash.** `git diff HEAD` was empty after all three. 1. The base `check-changeset-no-major.mjs` restored over the head (on-disk blob = the base blob). The repository test "declares no pending `major` the gate refuses — run as CI runs it" goes red on its assertion with the base gate's own message: "A changeset declares a `major` bump: @object-ui/types (.changeset/12334-objectstack-18-sync-major.md:2) …". The other red tests are the new exports the base lacks. 2. `minVersionOf`'s lower-bound reader put back to plain `X.Y.Z`: 5 tests red, all prerelease-floor pins. 3. Live negative control: `packages/core/package.json` given a union with a prerelease branch. The gate exits 1 with `@object-ui/core [unreadable-range] … cannot order "18.0.0-next.1" against "17.0.0"`. ## Acceptance notes (observations, not filed) - `.github/workflows/changeset-release.yml`, the comment on "Clear pending changesets for the publish branch", still describes Changesets 2's `pre.json.changesets`. It says this repository has no `pre.json` and no `.changeset/pre/`, which is false once this lands. The step's code already removes `.changeset/pre/*.md`, so behaviour is unaffected. The file is governed and outside this PR's surface. Carrier: none. ## Landing holds - `AGENTS.md` is a governed surface (`node scripts/check-governed-queue-guard.mjs --test` names it), so this PR stays draft until a `GOVERNED_APPROVERS` approval. - Every row of the pre-release list on objectui#12334 (`6164681402` and its updates) must be closed, or released by the maintainer, before this PR goes ready. That check is the seat's. ## 维护者速读(草稿) **改了什么**:为 objectui 第一次发 18.x 做好准备,但本 PR 本身不发版。四件事:① 一个 changeset 把整个 fixed 组(40 个包)从 17 升到 18,对齐 `@objectstack` 18;② 进入 Changesets 的 pre 模式,标签 `next`,所以发出去的是 `18.0.0-next.N`,npm 的 `latest` 不动;③ 「禁止 major」门禁按您在 objectui#12030 的裁决收窄:只有正好把 objectui 带到 `@objectstack/spec` 所依赖的那个大版本的 major 才放行,其余照旧拦,原来那个靠手动设置的环境变量开关同时退役;④ spec 版本下限门禁学会读 `18.0.0-next.1` 这种预发布下限,否则发版命令会在发布前自己中止。另外顺手改正了 6 条待发 changeset 里在 18 下已不成立的半句话。 **为什么改**:您的指示是「objectui 的下一个版本,发 v18」。依赖已经在 objectui#12030、#12370 两步升到 `@objectstack` 18 的预发布线,但版本号没跟上;两道门禁在 18 预发布线上要么误拦(major 门禁),要么直接把发版命令卡死(下限门禁)。 **风险与代价(含回滚)**:合并本身不发包;真正的发布仍是您合并版本 PR 那一步。pre 模式下每次版本 PR 都会发 `next` 标签,直到 `@objectstack` 18 正式版后再执行 `changeset pre exit` 发 `18.0.0`。回滚办法:revert 本 PR,也就是删掉 `pre.json` 和那条 major changeset,门禁恢复原样。已知未验证的一处:发布流水线本身在 pre 模式下的实际运行,目前只按其清理步骤的写法推断能正常走。 **席位意见**: **你要做的**:批准本 PR,它改了 AGENTS.md,属于受管面。版本 PR 是否合并、何时发 `18.0.0-next.0`,由您决定。 --- _Generated by [Claude Code](https://claude.ai/code/session_01JZnppgHRp4sREcouhkQYDB)_ --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: os-zhuang <jack@objectstack.ai>
1 parent 140916c commit 6f3299f

14 files changed

Lines changed: 809 additions & 71 deletions

‎.changeset/11838-rename-expression-refs.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
Renaming a node in the flow designer now also updates the expressions that read its outputs, removing a node that is still referenced is refused, and the Problems panel reports a reference to a node that does not exist as an error (objectui#11838).
66

7-
Later nodes read a node's outputs by its id. A decision branch reads `x.decision == 'approve'`, and a record field reads `{x.field}`. Renaming `x` used to update its edges and boundary event, but these expressions still named `x`. The saved draft then read a node that no longer existed, and the Problems panel showed only a scope warning.
7+
Later nodes read a node's outputs by its id. A decision branch reads `x.decision == 'approve'`, and a record field reads `{x.field}` (in 18 a CEL value envelope, `{ dialect: 'cel', source: 'x.field' }`, since `@objectstack/spec` 18 refuses the single-brace token there, see objectui#12101). Renaming `x` used to update its edges and boundary event, but these expressions still named `x`. The saved draft then read a node that no longer existed, and the Problems panel showed only a scope warning.
88

99
- **The rename updates every expression that reads the node, in the same change.** This covers decision branches, edge conditions, value expressions, and `{x.field}` or `{{x.field}}` holes in text, including those inside a loop, parallel or try/catch region. Each expression is read with the expression parser. Only the node's name changes. A different identifier that contains the old id (`xy`), a field named like it (`y.x`), text inside quotes, and a variable the expression itself declares with the same name (`rows.exists(x, x.ok)`) are not changed.
1010
- **A rename that cannot update an expression safely is refused, and nothing changes.** If an expression that reads the node does not parse, the message under the ID field names it. The rename is also refused when the old or new id is also a variable name in the flow, because the expression could mean either one.

‎.changeset/11865-access-panels-shared-select.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
'@object-ui/app-shell': patch
33
---
44

5-
Studio's package record sharing overview picks each object's internal and external sharing model with the shared `Select`. That is the control Studio's object Settings tab already uses for the same two sharing models (objectui#11865, the overview's part of that card). A permission set's advanced facets keep their native selects for now: the shared `Select` adds bytes to the console's first load there, and the first-load budget has no room for them yet.
5+
Studio's package record sharing overview picks each object's internal and external sharing model with the shared `Select` (the external dial is gone in 18: Studio no longer offers `externalSharingModel`, see objectui#12353). That is the control Studio's object Settings tab already uses for the same two sharing models (objectui#11865, the overview's part of that card). A permission set's advanced facets keep their native selects for now: the shared `Select` adds bytes to the console's first load there, and the first-load budget has no room for them yet.
66

77
The overview's two dials were browser-native selects, so they looked and behaved differently from Studio's other dropdowns. They now use the shared Radix `Select`: the same trigger, dropdown and keyboard behaviour.
88

‎.changeset/11865-object-settings-shared-select.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
'@object-ui/app-shell': patch
33
---
44

5-
Studio's object Settings tab picks the sharing model, the external sharing model, the name field, the lifecycle field and the next highlight field with the shared `Select`, the control Studio's validation rule editor already picks with (objectui#11865, the object settings part of that card).
5+
Studio's object Settings tab picks the sharing model, the external sharing model (gone in 18: Studio no longer offers `externalSharingModel`, see objectui#12353), the name field, the lifecycle field and the next highlight field with the shared `Select`, the control Studio's validation rule editor already picks with (objectui#11865, the object settings part of that card).
66

77
The five pickers were browser-native selects, so they looked and behaved differently from Studio's other dropdowns. They now use the shared Radix `Select`: the same trigger, dropdown and keyboard behaviour.
88

‎.changeset/11880-grid-filter-handoff.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ An `object-view` grid now exports the filter it shows, and returns to page 1 whe
99
Two user-visible corrections, both on an `object-view` rendered by the registered renderer (a page node, the Studio's stored-view preview; a host that supplies `renderListView` already behaved this way):
1010

1111
- **The export carries the view's filter.** A named view's filter and an authored `table.defaultFilters` narrowed the rows on screen, but the server-streamed export (CSV, XLSX, JSON) was handed no filter and downloaded every record of the object. It now downloads the rows the view shows, as it already did for `table.filter`.
12-
- **Changing the filter returns the grid to page 1.** When a named view's filter or `table.defaultFilters` changed while the grid stayed mounted, the next query kept the old page index, which could ask for a page the new result does not have. It now returns to page 1, as `table.filter` already did.
12+
- **Changing the filter returns the grid to page 1.** When a named view's filter or `table.defaultFilters` changed while the grid stayed mounted, the next query kept the old page index, which could ask for a page the new result does not have. It now returns to page 1, as `table.filter` already did (for a named view's filter only in 18, where `ObjectView` no longer reads `table.defaultFilters`, see objectui#12030).
1313

1414
What did not change: which filter applies (each rung and each pair sends the same query and draws the same rows; in 18 the `table.defaultFilters` rung is retired, see objectui#12030), and a refused filter still draws the grid's malformed-filter panel and queries nothing. Nothing is added to or removed from any published type, schema or export.

‎.changeset/11880-repeater-datasource.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55

66
`element:repeater` reads the node-level `dataSource` binding first (objectui#11880, the repeater half of the objectui step of objectstack#11509, ruled A-narrow).
77

8-
- **Renderer (`@object-ui/components`).** A repeater bound only through `dataSource` now lists the records it names; it showed "No records" before. Its flat `properties.object` / `filter` / `sort` / `limit` stay read, as the fallback (spec 18 retires them as authored keys, see objectui#12030, and the renderer keeps this read for metadata written before), so a repeater that carries only the flat keys reads exactly as before. Where a node carries both, the precedence is the one `ElementDataSourceGate` applies to every object-bound block: the binding's `object`; the flat `filter` AND-combined with the binding's (and its saved view's), so neither is dropped; the binding's own `sort` and `limit`, else the flat key, else the saved view's. An unresolvable `view`, or a filter the merge refuses, shows the configuration-error panel and reads nothing. The registration now publishes the injected `dataSource` input; `object` stays required (until objectui#12085 dropped the flat query inputs).
8+
- **Renderer (`@object-ui/components`).** A repeater bound only through `dataSource` now lists the records it names; it showed "No records" before. Its flat `properties.object` / `filter` / `sort` / `limit` stay read, as the fallback (spec 18 retires them as authored keys, see objectui#12030, and the renderer keeps this read for metadata written before), so a repeater that carries only the flat keys reads exactly as before (superseded in 18 by objectui#12345: the repeater no longer reads the flat keys at all, alone or beside a binding, and reads its query from `dataSource` alone). Where a node carries both, the precedence is the one `ElementDataSourceGate` applies to every object-bound block: the binding's `object`; the flat `filter` AND-combined with the binding's (and its saved view's), so neither is dropped; the binding's own `sort` and `limit`, else the flat key, else the saved view's. An unresolvable `view`, or a filter the merge refuses, shows the configuration-error panel and reads nothing. The registration now publishes the injected `dataSource` input; `object` stays required (until objectui#12085 dropped the flat query inputs).
99
- **Schema (`@object-ui/types`).** `ElementRepeaterBlockSchema` declares `dataSource` as `@objectstack/spec`'s `ElementDataSourceSchema`, by reference, and its bag's `object` stays required (until objectui#12056's waiver, and retired in 18, see objectui#12030). Clause-②: the strict authoring face (`StrictAnyComponentSchema`) now ACCEPTS a repeater carrying `properties.object` plus a well-formed `dataSource`, which it refused as an unrecognized key (since 18 it refuses `properties.object` by name, so the accepted node carries the binding alone); and the tolerant face (`safeValidateSchema`) now JUDGES the binding, so a repeater whose `dataSource` the spec's own node schema refuses (a string, a non-string `object`, an undeclared member, a record-form `filter`) is refused at `dataSource` where it was passed through unjudged. The TypeScript node type derived from the arm types the binding. A repeater whose bag omits `object` is refused at `properties.object` on both faces, as before; retired in 18, see objectui#12030: such a repeater is accepted.

‎.changeset/12085-element-binding-inputs.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66

77
**Narrowing, no widening.** The `element:repeater` registration drops its `object` (which was `required: true`), `filter`, `sort` and `limit` inputs. The `element:number` registration drops its `object` and `filter` inputs, which the metric has not read since objectui#11880. The injected `dataSource` input is unchanged on both. In the manifest these registrations feed, a repeater bound only through `dataSource` now draws no diagnostic (it drew `missing-required-prop`), and each of those six flat keys now draws `unknown-prop`. No export is added or removed, and no input is added.
88

9-
**Rendering is unchanged.** The repeater still reads its flat `properties.object` / `filter` / `sort` / `limit` as the binding's fallback, for metadata written before the retirement. That read is not published as an authoring surface. The metric reads its query from `dataSource` only, as before.
9+
**Rendering is unchanged.** The repeater still reads its flat `properties.object` / `filter` / `sort` / `limit` as the binding's fallback, for metadata written before the retirement (until objectui#12345 removed that fallback in 18, so the repeater reads its query from `dataSource` alone). That read is not published as an authoring surface. The metric reads its query from `dataSource` only, as before.
1010

1111
objectstack's `sdui.manifest.json` is regenerated from these registrations at objectstack's next console pin bump; this release does not change that file.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
"@object-ui/types": major
3+
"@object-ui/core": major
4+
"@object-ui/i18n": major
5+
"@object-ui/react": major
6+
"@object-ui/components": major
7+
"@object-ui/react-runtime": major
8+
"@object-ui/sdui-parser": major
9+
"@object-ui/fields": major
10+
"@object-ui/layout": major
11+
"@object-ui/data-objectstack": major
12+
"@object-ui/cli": major
13+
"@object-ui/create-plugin": major
14+
"@object-ui/runner": major
15+
"@object-ui/auth": major
16+
"@object-ui/permissions": major
17+
"@object-ui/mobile": major
18+
"@object-ui/plugin-ai": major
19+
"@object-ui/plugin-calendar": major
20+
"@object-ui/plugin-charts": major
21+
"@object-ui/plugin-chatbot": major
22+
"@object-ui/plugin-dashboard": major
23+
"@object-ui/plugin-designer": major
24+
"@object-ui/plugin-detail": major
25+
"@object-ui/plugin-editor": major
26+
"@object-ui/plugin-form": major
27+
"@object-ui/plugin-gantt": major
28+
"@object-ui/plugin-grid": major
29+
"@object-ui/plugin-kanban": major
30+
"@object-ui/plugin-list": major
31+
"@object-ui/plugin-map": major
32+
"@object-ui/plugin-markdown": major
33+
"@object-ui/plugin-report": major
34+
"@object-ui/plugin-timeline": major
35+
"@object-ui/plugin-tree": major
36+
"@object-ui/plugin-view": major
37+
"@object-ui/collaboration": major
38+
"@object-ui/app-shell": major
39+
"@object-ui/providers": major
40+
"@object-ui/console": major
41+
"object-ui": major
42+
---
43+
44+
objectui moves to major 18, following `@objectstack/*` from 17 to 18 (objectui#12334). objectui's major is not a count of its own breaking changes: it tracks the major of the `@objectstack/spec` its packages depend on, so that the same major means compatible across the two projects. These packages already declare `@objectstack/*` on the 18 line (objectui#12030), so every package in the fixed release group crosses to 18 together. It is the one `major` that rule admits: objectui's own breaking changes ship as `minor`, described in their entries.
45+
46+
The 18 line is released from Changesets pre mode on the `next` tag (`.changeset/pre.json`), as `@objectstack/*` 18 is: these releases are `18.0.0-next.N` on the npm `next` dist-tag, and they do not move `latest`. The first `18.0.0` on `latest` comes when `@objectstack` 18 is generally available and this repository leaves pre mode.
47+
48+
What a consumer must do to take it is in the `@objectstack/*` 18 entry of this release (objectui#12030): move its own `@objectstack/*` packages to the 18 line at the same time.

‎.changeset/pre.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"mode": "pre",
3+
"tag": "next"
4+
}

‎AGENTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ AGENTS.md 的「只跑受影响的包」指的是**用上面的路径过滤缩
282282
- minor/patch **独立演进**——objectstack 没动时不必跟发;objectui 自己的改动照常用 changeset 推进(从当前 major 起步,如 `11.0.0 → 11.1.0`)。
283283
- objectstack 跨 major(→12)时,下一次 objectui 发版一并把 major 提到 `12`。
284284
- 推论:**changeset 里不要声明 `major`** —— fixed 组任一 `major` 都会把全组推上去、脱离 objectstack 的节奏(如 17.x 期间被推到 18)。objectui 自身的破坏性变更也标 `minor`(在正文里写清 breaking 语义即可);唯一例外是跟随 objectstack 跨 major 的那一次同步升级。
285-
- **这一条现在由 CI 机械强制** —— `scripts/check-changeset-no-major.mjs` 在任一 changeset 声明 `major` 时退出非零,由 `.github/workflows/changeset-guard.yml` 跑(它是唯一以 `.changeset/**` 为**触发**路径的 workflow。这里曾写「`ci.yml`/`lint.yml` 都把 `**/*.md` 和 `.changeset/**` 列进 `paths-ignore`,只加 changeset 的 PR 不会启动任何 workflow」——**已不成立,别照它做判断**:objectui#3523 step 2 把 `paths-ignore` 从这两个 workflow 的 `pull_request` 上删掉了,今天它**只**留在 `push` 触发上;PR 的路径判断改在 job 内做 —— `ci.yml` 的 `Decide whether this change needs a full run` 步骤,`lint.yml` 有同名的一份。所以 md-only / changeset-only 的 PR **照常启动**这两个 workflow 并产出 required context —— 实测 PR #3856(只改一个 `.md`)起了 16 个 check、PR #4339(只给 AGENTS.md 加一行)起了 17 个。真正被跳过的是重活:那个 job 内开关的排除表逐条**等于** `push` 的 `paths-ignore`(仍含 `**/*.md` 与 `.changeset/**`),changeset-only 的 PR 里这两个 workflow 每一步都 skip。这才是 changeset-guard.yml 今天仍必须独立、且以 `.changeset/**` **反向**触发的理由:它跑在那个 job 内开关之外,免安装免构建,是唯一判得到 changeset-only PR 的东西。见 objectui#3523 step 2 / objectui#3857),`pnpm test` 里另有一条仓库状态断言兜底。跟随 objectstack 跨 major 的那一次发版设 `OBJECTUI_ALLOW_MAJOR=1` 放行。前情:objectui#3161/#3159/#3160/#3225 四个 changeset 在 17.x 期间标了 `major`(17 个包条目),足以把 39 个包发成 `18.0.0`。
285+
- **这一条现在由 CI 机械强制** —— `scripts/check-changeset-no-major.mjs` 在任一 changeset 声明 `major` 时退出非零,由 `.github/workflows/changeset-guard.yml` 跑(它是唯一以 `.changeset/**` 为**触发**路径的 workflow。这里曾写「`ci.yml`/`lint.yml` 都把 `**/*.md` 和 `.changeset/**` 列进 `paths-ignore`,只加 changeset 的 PR 不会启动任何 workflow」——**已不成立,别照它做判断**:objectui#3523 step 2 把 `paths-ignore` 从这两个 workflow 的 `pull_request` 上删掉了,今天它**只**留在 `push` 触发上;PR 的路径判断改在 job 内做 —— `ci.yml` 的 `Decide whether this change needs a full run` 步骤,`lint.yml` 有同名的一份。所以 md-only / changeset-only 的 PR **照常启动**这两个 workflow 并产出 required context —— 实测 PR #3856(只改一个 `.md`)起了 16 个 check、PR #4339(只给 AGENTS.md 加一行)起了 17 个。真正被跳过的是重活:那个 job 内开关的排除表逐条**等于** `push` 的 `paths-ignore`(仍含 `**/*.md` 与 `.changeset/**`),changeset-only 的 PR 里这两个 workflow 每一步都 skip。这才是 changeset-guard.yml 今天仍必须独立、且以 `.changeset/**` **反向**触发的理由:它跑在那个 job 内开关之外,免安装免构建,是唯一判得到 changeset-only PR 的东西。见 objectui#3523 step 2 / objectui#3857),`pnpm test` 里另有一条仓库状态断言兜底。跟随 objectstack 跨 major 的那一次同步升级由脚本按 manifest 自行判定放行,不靠开关:只有 fixed 组成员上的 `major`、且该组当前 major + 1 正好等于组内 manifest 在 `dependencies`/`peerDependencies`/`optionalDependencies` 里声明的 `@objectstack/spec` 范围的 major 时才放行,其余照旧拦(维护者裁决,objectui#12030 评论 6149296149;判据的权威表述是该脚本的文件头);Changesets pre 模式下已被 `changeset version` 消费、挪进 `.changeset/pre/` 的 changeset 不再读。前情:objectui#3161/#3159/#3160/#3225 四个 changeset 在 17.x 期间标了 `major`(17 个包条目),足以把 39 个包发成 `18.0.0`。
286286
- 这是约定优先于 semver 纯粹性的取舍(为可维护/好记),因此 objectui 的 major 不代表「它自身 API 的破坏性变更次数」。`@object-ui/site` 与 `@object-ui/example-*` 在 `ignore` 列表,不随组联动。
287287

288288
### 多 agent 协作纪律(并行修改本仓库,务必遵守)

‎content/docs/guide/ci-cd-pipeline.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2576,8 +2576,13 @@ Runs `scripts/check-changeset-no-major.mjs`, which fails if any pending changese
25762576
breaking changes of our own as `minor` and describe the break in the changeset body.
25772577

25782578
The one release that legitimately bumps the major is the one following `@objectstack` across
2579-
its major; it sets `OBJECTUI_ALLOW_MAJOR=1`. `pnpm test` asserts the same repository state, so
2580-
the rule survives this workflow being skipped.
2579+
its major, and the script admits it by itself, with no switch to set: a `major` on a `fixed`-group
2580+
package passes only when the group's current major plus one equals the major of the
2581+
`@objectstack/spec` range the group's own manifests declare in `dependencies`,
2582+
`peerDependencies` or `optionalDependencies`; every other `major` is refused. In Changesets pre
2583+
mode, a changeset that `changeset version` has consumed moves to `.changeset/pre/` and is no longer
2584+
read. The script's header is the authoritative statement of the criterion. `pnpm test` asserts
2585+
the same repository state, so the rule survives this workflow being skipped.
25812586

25822587
#### Second job: Changeset Overwrite Report
25832588

0 commit comments

Comments
 (0)