Skip to content

chore(deps): 把 @objectstack 家族同步到 17.0.0-rc.1,消除双版本 spec 图 - #3189

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-3182-spec-family-lockstep
Aug 2, 2026
Merged

chore(deps): 把 @objectstack 家族同步到 17.0.0-rc.1,消除双版本 spec 图#3189
os-zhuang merged 1 commit into
mainfrom
claude/issue-3182-spec-family-lockstep

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #3182

问题

#3178 只把 @objectstack/spec 升到了 17.0.0-rc.1,家族里其余包(client / core / formula / lint,以及经 lint 间接引入的 sdui-parser)仍停在 17.0.0-rc.0。而这几个包对 spec 的依赖是精确版本而非 caret:

@objectstack/client@17.0.0-rc.0  -> spec "17.0.0-rc.0"
@objectstack/core@17.0.0-rc.0    -> spec "17.0.0-rc.0"
@objectstack/formula@17.0.0-rc.0 -> spec "17.0.0-rc.0"
@objectstack/lint@17.0.0-rc.0    -> spec "17.0.0-rc.0"

于是合并后的 main 上同时躺着两份 spec:objectui 自己的代码读 rc.1,每个 @objectstack/* 包则从各自嵌套的 node_modules 里读 rc.0。

这不只是「版本号不整齐」这么轻。本仓有多处 guard 建立在单一契约这个不变量上,而它们判定的依据是同一性、不是版本字符串,所以双份 spec 会让它们静悄悄地失准:

  • spec-subschema-parity.test.ts 靠 zod schema 对象的引用同一性来区分「真 re-export」与「fork」。两份 spec 让每个 schema 都成了不同对象,于是真正的 re-export 会开始被读成 fork —— 或者反过来漏掉一个 fork,取决于两侧各自解析到了哪一份。
  • scripts/check-spec-symbol-derivation.mjsspec-symbol-parity.test.tscreateRequire 解析 spec 的 .d.ts 再交给 TS checker。装了两份的时候,checker 究竟看到哪一份 declaration file,取决于解析顺序而不是意图。

改动

把剩余的 ^17.0.0-rc.0 range 一并抬到 ^17.0.0-rc.1(packages/app-shellpackages/corepackages/data-objectstackapps/consoleapps/site),并刷新 lockfile。

原先声明的 range 其实已经允许 rc.1 —— 钉死它的是 lockfile。抬 range 的意义在于把下限写明:今后任何一次 install 都不可能再悄悄滑回某个会顺手把 rc.0 拖进来的家族成员。rc.1 的家族成员把 spec 精确钉在 17.0.0-rc.1,所以现在的图是构造上收敛到一份,而不是碰巧收敛。

没有产品行为改动。

验证

单份 spec 探针

$ ls node_modules/.pnpm | grep '^@objectstack+'
@objectstack+client@17.0.0-rc.1_ai@7.0.37_zod@4.4.3_
@objectstack+core@17.0.0-rc.1_ai@7.0.37_zod@4.4.3_
@objectstack+formula@17.0.0-rc.1_ai@7.0.37_zod@4.4.3_
@objectstack+lint@17.0.0-rc.1_ai@7.0.37_zod@4.4.3_
@objectstack+sdui-parser@17.0.0-rc.1
@objectstack+spec@17.0.0-rc.1_ai@7.0.37_zod@4.4.3_

图里只剩一份 spec。各家族包实际解析到的 spec:

client  -> spec 17.0.0-rc.1
core    -> spec 17.0.0-rc.1
formula -> spec 17.0.0-rc.1
lint    -> spec 17.0.0-rc.1
root    -> spec 17.0.0-rc.1

lockfile 里 @objectstack/* 的 snapshot key 也只剩 rc.1 一档(改前是 spec@17.0.0-rc.0spec@17.0.0-rc.1 并存)。

check:spec-symbols

$ pnpm check:spec-symbols
✅  spec symbol derivation: 1200 files scanned against 4344 spec export names;
    8 declared dialects, 75 untriaged collisions in 18 packages.
EXIT=0

原正文「阻塞 2」的四处对账(InboxNotificationFieldNode、以及 JoinNode / PerformanceConfig 两条陈旧 DEBT 台账)已由 #3178 全部处理完,统一到单份 spec 之后依然是绿的 —— 本 PR 无需再动 spec-symbol-parity.test.ts 或 DEBT 台账。

$strip$strict 回归

rc.1 把一批 zod schema 从 $strip 翻成 $strict(strict 会拒绝未知键而不是静默丢弃)。这批改动早在 #3178 就随 spec 落到 main 上了,本 PR 只是在统一图之后补做回归证明。在 rc.1 上实测各 subpath 的严格面(递归遍历 shape,统计 catchall 为 never 的 object schema):

subpath $strict $strip
automation 11 109
ui 23 234

翻严的 schema 根落在这些族上:

  • automation —— FlowSchema / FlowNodeSchema / FlowEdgeSchema / FlowVersionHistorySchemaApprovalNodeConfigSchema / ApprovalNodeApproverSchema / ApprovalEscalationSchema
  • ui —— AppSchema / AppBrandingSchema / AppContextSelectorSchemaDashboardSchema / DashboardNavItemSchemaFormViewSchema / FormButtonConfigSchema / FieldWidgetPropsSchema、以及整族导航项(NavigationContributionSchemaObjectNavItemSchemaPageNavItemSchemaActionNavItemSchemaComponentNavItemSchemaGroupNavItemSchemaReportNavItemSchemaUrlNavItemSchema)

对应的解析面(packages/types 的 zod / parity 套件、app-shell 的 flow / approval / metadata-admin 套件、plugin-dashboard、plugin-form)都在全量 vitest 里跑到了,结果见下。没有出现「合法元数据现在被拒」的回归;若出现,按 contract-first 原则会另开 issue 记录而不是放松 schema。

全量结果

全量 vitest(pnpm test,unit / dom / dom-heavy / console 四个 project 全跑):

Test Files  803 passed | 1 skipped (804)
     Tests  9397 passed | 25 skipped (9422)
  Duration  806.19s

针对「引用同一性」这条最容易被双份 spec 击穿的面,单独再跑一遍:

$ pnpm vitest run --project unit \
    spec-subschema-parity spec-symbol-parity spec-ui-schema-reexports spec-derived-unions
Test Files  4 passed (4)
     Tests  71 passed (71)
  Duration  3.41s
EXIT=0

其余 gate:

$ pnpm build            -> Tasks: 43 successful, 43 total
$ pnpm type-check       -> Tasks: 78 successful, 78 total
$ pnpm lint             -> Tasks: 45 successful, 45 total   (0 errors)
$ pnpm changeset:check  -> ✅  All workspace packages are in the changeset fixed group.  EXIT=0

未运行的套件:Playwright e2e(test:e2e / test:e2e:live / test:e2e:import-*)—— 需要浏览器与实际后端服务栈,不在本次容器内运行(且按仓库多 agent 服务纪律不应占用共享端口)。这些是 CI 的职责。

关于并行任务

#3181 正在给 app-shell 加 tsconfig.typetests.json 与一条 CI lane;本 PR 未触碰这两处文件。本次对账无需修改 spec-symbol-parity.test.ts,因此与 #3181 无文件重叠。

版本策略

按 AGENTS.md「版本号策略」,changeset 标 minor —— fixed 组任一 major 都会把全组 40 个包推上去、脱离 objectstack 的节奏。

🤖 Generated with Claude Code


Generated by Claude Code

#3178 bumped only @objectstack/spec to 17.0.0-rc.1. client/core/formula/lint
depend on spec at an EXACT version, so main resolved two spec copies: objectui
code saw rc.1 while every @objectstack/* package saw rc.0 from its own nested
node_modules.

That breaks the single-contract invariant the repo's guards rely on:
spec-subschema-parity.test.ts distinguishes re-export from fork by reference
identity, and check-spec-symbol-derivation.mjs / spec-symbol-parity.test.ts
resolve spec's .d.ts via createRequire — with two copies, which one they see
depends on resolution order.

Raise the remaining ^17.0.0-rc.0 ranges to ^17.0.0-rc.1 so the floor is
explicit. The rc.1 family members pin spec at 17.0.0-rc.1 exactly, so the graph
converges on one copy by construction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5
@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Aug 2, 2026 9:11am

Request Review

@os-zhuang
os-zhuang marked this pull request as ready for review August 2, 2026 09:13
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 2, 2026
Merged via the queue into main with commit d3584c6 Aug 2, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-3182-spec-family-lockstep branch August 2, 2026 09:13
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 28.1 KB 350 KB
Entry file index-BLIovOy5.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 8.47KB 3.09KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 7.57KB 2.97KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 22.10KB 4.37KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.12KB 3.41KB
auth (LoginForm.js) 17.86KB 5.29KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.43KB 2.09KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 35.76KB 9.11KB
auth (createAuthenticatedFetch.js) 4.37KB 1.69KB
auth (index.js) 2.35KB 1.07KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 4.91KB 0.87KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 18.38KB 4.49KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 3.65KB 1.42KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.25KB 0.53KB
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) 475.95KB 104.41KB
core (index.js) 2.25KB 0.80KB
create-plugin (index.js) 9.28KB 2.98KB
data-objectstack (index.js) 136.20KB 34.74KB
fields (index.js) 223.45KB 54.66KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 2.46KB 0.96KB
i18n (pickLocalized.js) 1.70KB 0.83KB
i18n (provider.js) 5.37KB 1.72KB
i18n (useObjectLabel.js) 26.14KB 6.07KB
i18n (useSafeTranslation.js) 3.26KB 1.44KB
layout (index.js) 38.47KB 10.67KB
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.74KB
mobile (index.js) 1.50KB 0.62KB
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) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.05KB 1.53KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.71KB 3.79KB
plugin-calendar (index.js) 44.90KB 12.35KB
plugin-charts (index.js) 60.53KB 17.12KB
plugin-chatbot (index.js) 180.09KB 42.72KB
plugin-dashboard (index.js) 111.87KB 28.82KB
plugin-designer (index.js) 210.51KB 42.50KB
plugin-detail (index.js) 224.52KB 54.98KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 111.38KB 26.93KB
plugin-gantt (index.js) 162.26KB 39.53KB
plugin-grid (index.js) 184.69KB 48.91KB
plugin-kanban (index.js) 47.82KB 13.18KB
plugin-list (index.js) 104.87KB 25.31KB
plugin-map (index.js) 16.80KB 5.24KB
plugin-markdown (index.js) 13.65KB 4.67KB
plugin-report (index.js) 40.48KB 10.57KB
plugin-timeline (index.js) 25.76KB 7.32KB
plugin-tree (index.js) 8.34KB 2.82KB
plugin-view (index.js) 83.54KB 20.39KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 19.28KB 6.38KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.02KB 0.55KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 2.46KB 1.21KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 0.20KB 0.18KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.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 (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
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 join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@objectstack/spec 仍锁在 17.0.0-rc.0:升到 rc.1 会产生双版本 spec 图,并打红 check:spec-symbols

2 participants