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

chore(deps): narrow the React peer range to ^19.0.0 (objectui#13465) - #13481

Merged
os-zhuang merged 3 commits into
mainfrom
claude/project-thread-8vyi5c
Oct 25, 2026
Merged

os-zhuang merged 3 commits into
mainfrom
claude/project-thread-8vyi5c

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Elon · project thread

Fixes #13465

Clause-②: no
Metadata-protocol: none

维护者速读(草稿)

  • 改了什么: 所有向宿主要 React 的 objectui 包,把 react / react-dom 的 peer 依赖从 ^18.0.0 || ^19.0.0 收窄到 ^19.0.0(实测 31 个包、56 条声明;卡上写的 33 个是旧计数)。AGENTS.md §2 和技能里的同一句「React 18+」改成「React 19」;脚手架 create-plugin 生成的新插件同样只声明 19。
  • 为什么改: 我们对外承诺能跑在 React 18 上,但仓里从没装过、测过 React 18。按你的裁决 A:只卖我们测过的。
  • 风险与代价(含回滚): 还停留在 React 18 的宿主,装下一版时会收到 peer 依赖警告或被拒装,需要先升级到 React 19。目前没有已知的 React 18 用户(未实测 npm 下游)。每个包一个 minor changeset 并写明 breaking,不动 major。回滚 = revert 本 PR。
  • 席位意见:
  • 你要做的(一个动作):

What changed

  • 31 manifests, 56 peer declarations (31 react + 25 react-dom) now read ^19.0.0. Derived by any spelling on cd70b78: no other React peer spelling and no @types/react peer exists in the workspace.
  • Pins that hold the range, moved with it (each would go red otherwise):
    • react-peer-range-norm-3741.test.ts: REACT_PEER_NORM is now ^19.0.0, with a docblock paragraph saying why the 18 arm went.
    • doc-version-claims.test.ts: the 12 package README peer lines are asserted verbatim against their manifests, so the READMEs move; ledger keys follow (PEER_19, the react-runtime prose line, the two plugin-skeleton samples). The two React 18+ unanchored entries are deleted: "React 19" carries no version token the scan records, and the ratchet refuses an entry that outlives its claim.
    • QUICK_REFERENCE.md: the React row reads 19.x; quick-reference-current-release-4143.test.ts derives it from the peer majors.
  • AGENTS.md §2 (governed): "React 18+ (Hooks)" → "React 19 (Hooks)", per the ruling.
  • skills/** (published skills face), two files, net line delta 0, rewrite in place:
    • skills/objectui/SKILL.md: the Tech Stack line is the verbatim mirror of AGENTS.md §2 (the doc-version-claims ledger states it is), so it moves with §2 to keep the two agent-facing texts in sync.
    • skills/objectui/guides/plugin-development.md: the plugin skeleton's peerDependencies now say ^19.0.0. A plugin built on @object-ui/* packages that only accept React 19 cannot honestly offer React 18 to its host; same change as the create-plugin generator below.
  • @object-ui/create-plugin: a generated plugin's peers are ^19.0.0 (user-visible, own minor changeset). The hand-written skeleton in content/docs/guide/plugins.md moves the same way.
  • Prose and comments that cited the old range: content/docs/guide/troubleshooting.md, two "Built with React 18+" lines in packages/components docs, and comment-only edits in useGlobalUndo (@object-ui/react), inline-markdown (@object-ui/components), and scaffold-dependencies plus its test (@object-ui/cli; no release needed for a comment, the gate is satisfied by the other changesets).
  • 32 changesets, .changeset/13465-react-peer-*.md: one minor per package with a Breaking note (no major, per 版本号策略).
  • pnpm-lock.yaml is unchanged: workspace importers do not record peer ranges, and pnpm install --frozen-lockfile passed on the narrowed manifests.

Gates run locally (head 08400c4)

pnpm exec vitest run scripts/ packages/create-plugin/ packages/cli/ :: exit 0   (227 files passed, 2 skipped; 6209 tests)
node scripts/sync-quick-reference-release.mjs --check :: exit 0
node scripts/check-changeset-presence.mjs :: exit 0
node scripts/check-changeset-no-major.mjs :: exit 0
pnpm check:new-line-citations :: exit 0
pnpm exec eslint (the 7 changed .ts/.tsx files, listed by git diff --name-only) :: exit 0

Acceptance notes

  • Not done, out of scope: no runtime code changes here. Code that exists only to keep React 18 working, if any, was not searched for; it is a possible cleanup, not a defect. dropped — no defect.

  • The peer narrowing of a published range owes a contract-review-tier review before the queue (claim 6391446264); the skills/** hunk owes the same (seat comment 6391465213).

  • Adds no product-specific widget, dialog, hook or string (see AGENTS.md › Product-neutral renderer)

🤖 Generated with Claude Code

https://claude.ai/code/session_01Erxd3BYXhV2mQMatxGZ9yg

Every workspace package that asks its host for React now declares
`react` / `react-dom` as `^19.0.0` instead of `^18.0.0 || ^19.0.0`:
31 packages, 56 peer declarations (31 react + 25 react-dom). Nothing in
the tree ever installed or tested React 18, so the 18 arm was a published
promise with no test behind it. Maintainer ruling A on the card.

Moves with it, because the repo pins the range in several places:
- react-peer-range-norm-3741 test: the norm is now `^19.0.0`;
- the 12 package README peer lines and doc-version-claims' ledger keys;
- QUICK_REFERENCE.md's React row (the release-block test reads the majors);
- AGENTS.md section 2 and its verbatim mirror in skills/objectui/SKILL.md;
- create-plugin's generated peers, the plugin skeletons in the docs, the
  troubleshooting page and comments that cited the old range.

One minor changeset per package with a breaking note (no `major`, per the
version-alignment policy).

Claude-Session: https://claude.ai/code/session_01Erxd3BYXhV2mQMatxGZ9yg
Co-authored-by: Claude <noreply@anthropic.com>
"React 19" carries no version token the scan records, so the
troubleshooting page and the skills Tech Stack mirror no longer make a
claim the inventory excuses; the ratchet requires their entries to go.

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

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 1 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/25685-one-react-line.md

  • names scaffold-dependencies.ts → packages/cli/src/utils/scaffold-dependencies.ts — edited by this change

    One react line: every manifest that pins react / react-dom now pins 19.3.0, and every @types/react / @types/react-dom pin is 19.3.0, matching the root pnpm.overrides. The objectstack monorepo's @objectstack/client-react requires react ^19.3.0, and a second @types/react copy broke @object-ui/plugin-view's declaration build in the merged tree. The CLI's scaffold (REACT_RANGE and the shared dev-dependency map in scaffold-dependencies.ts) quotes the same pins, as its anchor test requires.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with c85408f68 (merge-base with origin/main): 58 file(s) changed outside .changeset/, read against 2 pending declaration(s) that publish a body (3 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 85 chunks) 3014.5 KB 3496.0 KB
Main entry chunk (gzip) 80.3 KB 350 KB
Entry file index-mAn66EKm.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (buildIdentity.js) 0.80KB 0.49KB
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 21.41KB 7.90KB
app-shell (runtime-config.js) 24.52KB 8.48KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 45.59KB 12.03KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.67KB 6.12KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.74KB 3.94KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 42.84KB 11.66KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 8.84KB 3.61KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 614.94KB 150.52KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.92KB 9.50KB
data-objectstack (index.js) 253.04KB 70.68KB
fields (index.js) 295.90KB 75.88KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 41.17KB 11.96KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (ServerReadScope.js) 4.03KB 1.82KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.99KB 0.43KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.91KB
plugin-calendar (index.js) 55.41KB 16.19KB
plugin-charts (index.js) 88.30KB 24.33KB
plugin-chatbot (core.js) 5.22KB 2.18KB
plugin-chatbot (index.js) 237.93KB 56.26KB
plugin-dashboard (index.js) 147.15KB 39.95KB
plugin-designer (index.js) 232.83KB 50.01KB
plugin-detail (index.js) 267.21KB 71.14KB
plugin-editor (index.js) 2.21KB 1.04KB
plugin-form (index.js) 185.46KB 48.48KB
plugin-gantt (index.js) 178.19KB 45.06KB
plugin-grid (index.js) 278.30KB 77.57KB
plugin-kanban (index.js) 64.27KB 19.81KB
plugin-list (index.js) 149.60KB 39.26KB
plugin-map (index.js) 27.11KB 8.99KB
plugin-markdown (index.js) 13.79KB 4.79KB
plugin-report (index.js) 46.42KB 13.06KB
plugin-timeline (index.js) 39.30KB 11.87KB
plugin-tree (index.js) 15.25KB 5.38KB
plugin-view (index.js) 94.26KB 24.27KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 129.13KB 42.23KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.71KB 2.11KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 1.13KB 0.65KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.78KB 2.70KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (product-blocks.js) 0.20KB 0.19KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读 · PR #13481 @ 08400c4479bc64ffd63d6db47ff9f5fdbcb9e169 · domain:ui#4 · 2026-10-25T01:01Z

  • 改了什么: objectui 全部 31 个包把 react / react-dom 的 peer 依赖从「18 或 19」收窄为只接受 19(56 条声明);AGENTS.md §2 与对外技能里那句「React 18+」改为「React 19」;脚手架生成的新插件也只声明 19。没有改任何运行时代码。
  • 为什么改: 执行你对 decision: React 18 is a published peer contract (^18 || ^19 in 33 packages) that is never installed or tested — narrow to ^19, or add a React 18 lane? #13465 的裁决 A(「13465 同意」):仓里从没装过、测过 React 18,对外不再承诺它。
  • 风险与代价(含回滚): 还在 React 18 上的宿主装下一版时会收到 peer 警告或被拒装,要先升 19;目前没有已知的 18 用户(npm 下游未实测)。每个包一个 minor changeset 并写明 Breaking,不动 major。回滚 = revert 本 PR。
  • 席位意见: 通过。diff 与裁决逐条对得上,CI 全绿;改动面只多了为让门禁转绿而必须同步的测试、README 和文档句子,以及技能里镜像 AGENTS.md 的两行(净增 0 行)。技能面另欠一次契约复审档复核,已挂 needs:contract-review,由总监每小时复审。
  • 你要做的(一个动作): 请 hotlong 或 os-zhuang 在本 PR 上点 Approve(已请审)。批准在案后由本席落地。

席位核对 — ACCEPT (TIER_DEFAULT part)

Reviewer of record: session_01XWGTsmqrtrt1Zqh1ioWqsT (seat 4). Implemented-by: claude/project-thread-8vyi5c (card session session_01Erxd3BYXhV2mQMatxGZ9yg). Card objectui#13465, claim 6391446264, surface amendment 6391465213.

  1. Shape: draft, base main, Fixes #13465 first; author objectstack-fleet[bot] (relay). 90 files, +375 −127: 31 manifests, 32 changesets, 12 READMEs, QUICK_REFERENCE.md, three scripts/__tests__ pins, docs, comment-only lines, create-plugin template, AGENTS.md §2, two skills/** files — all inside the amended surface. pnpm-lock.yaml untouched.
  2. Premise measured: git grep '^18.0.0 || ^19.0.0' over *.json on objectui origin/main gives 56 lines — the 56 declarations the dev narrowed (31 react + 25 react-dom); the ruling's "33" reads as 31. AGENTS.md:36 and skills/objectui/SKILL.md Tech Stack line both move "React 18+" → "React 19", keeping the verbatim mirror the doc-version-claims ledger documents.
  3. Gates on this head: 33 check-runs success (Lint, Type Check, Test shards 1–16 + Test, Test (dist pins), Build & E2E, Build Docs, Repo Gates, changeset family, Line Citation Gate, Governed Surface Queue Guard, Bundle Analysis, label, Live E2E (informational)); 3 skipped (coverage, dependabot). mergeable_state: clean.
  4. Accepted deviations: the two React 18+ unanchored ledger entries are deleted, not re-keyed — "React 19" carries no version token the scan records and the ratchet refuses a dead entry. The ruling text "33 packages" is a stale count, not a scope cut.
  5. Out of scope: React-18-only code paths, if any, were not searched — dropped — no defect (a cleanup, not a defect).
  6. Landing: Tier H (AGENTS.md, skills/**). Stays draft with needs-user-decision until an APPROVED review from GOVERNED_APPROVERS; the skills/** face also needs a same-head ## Contract review PASS at CONTRACT_REVIEW_TIER (marker needs:contract-review hung now). Changeset prose: the seat read 13465-react-peer-react.md and spot-checked the others' frontmatter — each is minor with the same Breaking sentence; matches the diff.

Generated by Claude Code

Copy link
Copy Markdown
Collaborator

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 08400c4479bc64ffd63d6db47ff9f5fdbcb9e169
Local-runs: none
Scope: governed-text face — hits AGENTS.md (§2 Tech Stack line), skills/objectui/SKILL.md (Tech stack line), skills/objectui/guides/plugin-development.md (plugin skeleton peers); cited: the 31 packages/*/package.json peer declarations (56 lines), packages/create-plugin/src/templates.ts, scripts/__tests__/react-peer-range-norm-3741.test.ts, scripts/__tests__/doc-version-claims.test.ts, QUICK_REFERENCE.md, the 12 package READMEs, packages/cli/src/utils/scaffold-dependencies.ts (comment only); prose: 32 .changeset/13465-react-peer-*.md, content/docs/guide/{plugins,troubleshooting}.md.

① Derived judgments

  • Ruling conformance. Letter A on objectui#13465 (6386224339, 「13465 同意」): every react / react-dom peer narrows from ^18.0.0 || ^19.0.0 to ^19.0.0, one minor changeset per package with a breaking note, AGENTS.md §2 "React 18+" becomes "React 19". All present. The ruling's "33 packages" is the card's count at 7981384; the dev re-derived the set by spelling on cd70b78 and found 31 manifests, 56 declarations, no other spelling and no @types/react peer. A stale count, not a scope cut.
  • Governed text changes exactly the ruled line. AGENTS.md +1 −1; skills/objectui/SKILL.md +1 −1 (the verbatim mirror of §2 the doc-version-claims ledger documents, so leaving it would desync the two agent-facing texts); skills/objectui/guides/plugin-development.md +2 −2 (skeleton peers). Net line budget 0 on skills/** held; no new rule, no new sentence.
  • Declaration right. Peer ranges are not the metadata protocol and nothing in the accepted set widens, so Clause-②: no / Metadata-protocol: none; the published-contract narrowing is carried by the Breaking note in every changeset, which is objectui's shape for it.
  • Pins moved with the range, not deleted around it: REACT_PEER_NORM becomes ^19.0.0 with the ruling cited in its docblock; PEER_18_19 becomes PEER_19 and the 12 README peer lines stay asserted verbatim against their manifests; the two "React 18+" unanchored ledger entries are deleted because "React 19" carries no version token the scan records and the ratchet refuses an entry that outlives its claim. The generator (templates.ts) and the hand-written skeletons move the same way, so a new plugin cannot offer React 18 on packages that no longer accept it.
  • pnpm-lock.yaml unchanged: workspace importers record no peer ranges; --frozen-lockfile passed. The pending .changeset/25685-one-react-line.md sentence about scaffold-dependencies.ts stays true: this PR touches that file in a comment only and the 19.3.0 pins it describes are untouched.
  • Runtime untouched: no source behaviour changes; the only .ts/.tsx edits outside tests are comments.

② Semver level

32 changesets, each minor with a Breaking sentence (31 packages plus @object-ui/create-plugin for the generated manifest); objectui's version-alignment policy never declares major. The 36 check runs on the head are all success or skipped (Lint, Type Check, Test shards 1–16 and Test, dist pins, Build and E2E, Build Docs, Repo Gates, changeset family incl. Bump Policy and Claim Re-read, Line Citation Gate, Governed Surface Queue Guard, Bundle Analysis).

③ Boundary flags

  • Tier H still owed: AGENTS.md and skills/** need an APPROVED review from a GOVERNED_APPROVERS account (hotlong / os-zhuang requested). This record clears the contract-review leg only; needs-user-decision stays until that approval.
  • In-org consumers are on React 19 already (objectstack pins 19.3.0 via its one-react-line change), so the narrowing changes no install inside the org; external React 18 hosts, if any, now fail loudly at install. npm dependents were not measured.
  • React-18-only code paths, if any exist, were not searched (dropped, no defect); a later cleanup card, not this PR.

Implemented-by: session_01Erxd3BYXhV2mQMatxGZ9yg
Reviewed-by: session_01Bf4vhia9fHNXpqC1PCfxie

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 08400c4479bc64ffd63d6db47ff9f5fdbcb9e169
Local-runs: none
Scope: AGENTS.md, skills/objectui/SKILL.md, skills/objectui/guides/plugin-development.md + the 56 peerDependencies.react / react-dom lines across 31 packages/*/package.json and the create-plugin template those hunks describe

Director seat, summon #49 (session session_0162wFwDdLFGhaSvDdSnZ9Sx, account os-zhuang; served claude-fable-5-1 = CONTRACT_REVIEW_TIER; written as objectstack-fleet[bot] through the relay). Face: governed rule text (AGENTS.md, skills/**), the face the ui seat 4 marked needs:contract-review in 6391709813. Read-only: the diff hunks, the card objectui#13465 and its ruling A, the PR body, the head's check-runs. ⛔ Not an approval: the Tier H approval stays the maintainer's click.

① Derived judgments

  1. AGENTS.md:36 §2 "React 18+ (Hooks)" → "React 19 (Hooks)" (+1/−1). The governed rule narrows the declared host from "18 or newer" to 19 only. It states exactly what the same diff makes true in 56 peer declarations and the create-plugin template, and what ruling A on objectui#13465 ordered. Correct. No ⛔ rule is added or removed; the file's rule count is unchanged.
  2. skills/objectui/SKILL.md:122 "React 18+ (hooks)" → "React 19 (hooks)" (+1/−1). On origin/main this line mirrors AGENTS.md:36 (the only case difference, "hooks", pre-exists); after the diff the two still mirror each other, so the published skill tells an external author the same host rule the repository holds itself to. Correct.
  3. skills/objectui/guides/plugin-development.md:386–387: the sample plugin manifest's peer ranges ^18.0.0 || ^19.0.0 → ^19.0.0 (+2/−2), matching the scaffold the create-plugin template now emits. A guide that kept the old range would have taught a range the template no longer produces. Correct.
  4. Accepted-set change on the published face: a host on React 18 is no longer declared supported. That is a narrowing of a published declaration with no metadata key, value or type involved (Clause-②: no, Metadata-protocol: none on the body and in every changeset) — the declarations are right.

② Semver level

32 changesets, one per package plus the shared ones; the one read in full (13465-react-peer-react.md) is minor with a Breaking sentence naming the old and new range and the host upgrade path; the seat record 6391709813 spot-checked the rest for the same frontmatter and sentence. minor with a Breaking note is what objectui's 版本号策略 (AGENTS.md:280–284: a changeset never declares major; the fixed group follows objectstack's cadence) prescribes. Consistent.

③ Boundary flags

  • PR user.login is objectstack-fleet[bot] (relay); the attribution block names github_login: os-elon-musk (the card's project thread). No non-relay author.
  • Flag from the dev's body: the ruling text says "33 packages", the tree has 31 with React peers — a stale count in the ruling, not a scope cut; the seat record reads it the same way. Answered, no escalation.
  • Flag: two React 18+ unanchored ledger entries deleted rather than re-keyed, because "React 19" carries no version token the ledger scans and the ratchet refuses a dead entry. Read as correct: a ledger row with nothing to anchor would be a false claim.
  • No open_questions in the PR body; the ruling on decision: React 18 is a published peer contract (^18 || ^19 in 33 packages) that is never installed or tested — narrow to ^19, or add a React 18 lane? #13465 carried none. React-18-only code paths were not searched (the seat record's "dropped — no defect"); that is a cleanup question, not a contract one.
  • Check-runs on this head when read: 33 success, 3 skipped, 0 failed (mergeable_state: clean).

Implemented-by: claude/project-thread-8vyi5c
Reviewed-by: session_0162wFwDdLFGhaSvDdSnZ9Sx
Reviewed-by-account: os-zhuang

VERDICT: PASS

needs:contract-review leaves the PR in this act (same-head PASS on record). Landing stays Tier H: an APPROVED review from GOVERNED_APPROVERS (hotlong / os-zhuang, both requested), then the ui seat lands it.


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review October 25, 2026 01:46
@os-zhuang
os-zhuang enabled auto-merge October 25, 2026 01:46
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Review label cleared · approval of record os-zhuang APPROVED 2026-10-25T01:46:37Z · same-head contract review PASS 6392078557 · 2026-10-25T01:49Z

Director seat, summon #49 (session session_0162wFwDdLFGhaSvDdSnZ9Sx, account os-zhuang; written as objectstack-fleet[bot] through the relay; ledger objectstack-ai/objectstack#12708). Head 4265cca89dbb: the Tier H approval is on record and the governed-face contract review PASS stands on the same head, so needs-user-decision leaves the PR in this act (the director's review-label clearance; this seat does not land). Landing — pre-landing checks, pr_ready and automerge_enable through the relay — belongs to the domain:ui seat holding objectui#13465.


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 85 chunks) 3014.5 KB 3496.0 KB
Main entry chunk (gzip) 80.3 KB 350 KB
Entry file index-b6SjGPkv.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (buildIdentity.js) 0.80KB 0.49KB
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 21.41KB 7.90KB
app-shell (runtime-config.js) 24.52KB 8.48KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 45.59KB 12.03KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.67KB 6.12KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.74KB 3.94KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 42.84KB 11.66KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 8.84KB 3.61KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 614.94KB 150.52KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.92KB 9.50KB
data-objectstack (index.js) 253.04KB 70.68KB
fields (index.js) 295.90KB 75.88KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 41.17KB 11.96KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (ServerReadScope.js) 4.03KB 1.82KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.99KB 0.43KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.91KB
plugin-calendar (index.js) 55.41KB 16.19KB
plugin-charts (index.js) 88.30KB 24.33KB
plugin-chatbot (core.js) 5.22KB 2.18KB
plugin-chatbot (index.js) 237.93KB 56.26KB
plugin-dashboard (index.js) 147.15KB 39.95KB
plugin-designer (index.js) 232.83KB 50.01KB
plugin-detail (index.js) 267.21KB 71.14KB
plugin-editor (index.js) 2.21KB 1.04KB
plugin-form (index.js) 185.46KB 48.48KB
plugin-gantt (index.js) 178.19KB 45.06KB
plugin-grid (index.js) 278.30KB 77.57KB
plugin-kanban (index.js) 64.27KB 19.81KB
plugin-list (index.js) 149.60KB 39.26KB
plugin-map (index.js) 27.11KB 8.99KB
plugin-markdown (index.js) 13.79KB 4.79KB
plugin-report (index.js) 46.42KB 13.06KB
plugin-timeline (index.js) 39.30KB 11.87KB
plugin-tree (index.js) 15.25KB 5.38KB
plugin-view (index.js) 94.26KB 24.27KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 129.13KB 42.23KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.71KB 2.11KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 1.13KB 0.65KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.78KB 2.70KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (product-blocks.js) 0.20KB 0.19KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.