Skip to content

fix(layout): navigation-renderer 的 items 声明为 required —— 校验器不再放过必崩的节点 (#3987) - #3995

Merged
yinlianghui merged 2 commits into
mainfrom
claude/issue-3987-navigation-items-required
Aug 9, 2026
Merged

fix(layout): navigation-renderer 的 items 声明为 required —— 校验器不再放过必崩的节点 (#3987)#3995
yinlianghui merged 2 commits into
mainfrom
claude/issue-3987-navigation-items-required

Conversation

@yinlianghui

@yinlianghui yinlianghui commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Fixes #3987

这一条改的是什么

navigation-rendereritems input 补 required: true(packages/layout/src/index.ts,一行)。

NavigationRendererProps.items非可选NavigationItem[],渲染器也不给默认值;而
sdui-parser 只在 input.required 为真时报 missing-required-prop
(packages/sdui-parser/src/validate.ts:55-64)。所以在这一改动之前,
{ "type": "navigation-renderer" } 这个节点是校验零诊断 + 渲染必崩:
唯一保证崩溃的形状,恰好也是校验器唯一无话可说的形状。

这是 #3972(键的存在 × 类型 × ManifestInputType 表达力)的第四面:可选性
方向上与 #3900 / #3972 相反 —— 那两条是删假诊断,这条是收紧(新增一条 error 级诊断),
按 issue 里的 PM 分诊裁定实施,未重开讨论。

运行期复现(issue 正文是静态读出,这里是实测)

issue 按 file:line 推断"两处都吃 undefined"。实测一次(省略 items 渲染真实组件,
MemoryRouter + SidebarProvider,react 19.2.8 / happy-dom),结果确认崩溃,并修正
读点顺序:

PROBE constructor: TypeError
PROBE message: items is not iterable
PROBE first stack frames: TypeError: items is not iterable
    at collectPinnedItems (packages/layout/src/NavigationRenderer.tsx:1410:22)
    at packages/layout/src/NavigationRenderer.tsx:1242:11
    at mountMemo (react-dom-client.development.js:8777:23)
    at Object.useMemo (react-dom-client.development.js:26216:18)
  • 第一处无守卫的读点是 pinnedItems memo(:1242)调用的 collectPinnedItems
    (:1410for (const item of items))—— 抛 TypeError: items is not iterable,
    白屏而非降级。
  • 它前面的 activeNavId memo(resolveActiveNavItem,:1229)挡得住:内部 visit
    首行就是 if (!nodes) return
  • issue 另点的 filteredItems.slice()(:1247)静态上同样会抛,但永远走不到 ——
    :1242 先崩。

这次复现已经作为常驻见证进了 PR(见下),不是一次性探针。

钉子(两方向 + 对照)

注册级 —— packages/layout/src/__tests__/navigation-renderer-items-declaration.test.tsx
(与 #3972 同一把钉子的同一个文件,按键归拢):

  • items.required === true,两个注册键(bare 与 layout namespace)都钉;
  • 对照:basePath.required 必须保持 falsy —— 渲染器真的给了它默认值(basePath = '')。
    required 是逐个属性从组件读出的事实,不是一刀切;这条对照一旦翻红,就说明收紧从
    "缺了会崩的那个属性"扩散成了"所有声明的属性";
  • 编译期镜像:undefined extends NavigationRendererProps['items'] 为假。items 哪天变成
    items?:,这个文件当场 type-check 失败,声明不会悄悄漂回去;
  • 运行期见证:省略 items 渲染 toThrow(TypeError) + toThrow(/items is not iterable/);
    配对的另一半是"给了 items、省略可选的 basePath,渲染正常"。

端到端 —— examples/schema-catalog/test/pageheader-with-actions.test.tsx
(#3972 的 manifest 门钉就在这里,紧邻按活注册表建 manifest 的 diagnose() 助手):

  • 省略 items 的节点报 missing-required-prop,并断言 severity === 'error' 与 message 里的
    "items"(先断 unknown-component 为空 —— 不然 tag 掉出 manifest 时这个断言会因为根本没跑到
    required 循环而假绿);
  • 给了数组(空数组 / 真实 item + basePath)零诊断;
  • 对照:可选属性省略不报 missing-required-prop(navigation-rendererbasePath,
    以及同文件注册的 page-header 只写 title)。

同批对照测试的同步(#3900not-a-container 对照)

examples/schema-catalog#3900 的对照节点原本故意省略 items,注释写着
"它不是 required,所以省略不画任何东西" —— 这句被本改动作废。按 fixture triage 的
"补声明"处置:节点补上 items: [],让它只剩那一处故意植入的缺陷(childless 组件带
children),对照恢复单一事实;注释同步重写,并记下它两次是从相反方向得到同一个结论
(先前省略是因为写 items: [] 会撞 #3972type-mismatch)。断言 toContain(CONTAINMENT)
本来按 code 过滤、两种写法都绿 —— 所以这里改的是注释的真实性与 fixture 的单一事实性,
不是为了让它变绿。文件头的"Four things are pinned here"同步为五条。

反向验证(先预判后跑,变异未提交)

预判:撤掉 required: true → 注册级 2 条 + 端到端 1 条翻红;三组对照
(basePath 可选、给了 items 零诊断、page-header 只写 title)保持绿;
运行期崩溃见证也保持绿 —— 崩溃与声明无关,它是这条收紧的理由,不是它的后果,
所以它在变异下不该动。实测与预判逐条一致:

× declares `required: true` (namespace: undefined)  → expected undefined to be true
× declares `required: true` (namespace: layout)     → expected undefined to be true
× reports `missing-required-prop` for a `navigation-renderer` without `items`
  → omitting `items` drew no `missing-required-prop`: expected undefined to be truthy
✓ leaves `basePath` optional — the renderer defaults it (both namespaces)
✓ throws a TypeError instead of rendering an empty navigation
✓ renders fine when `items` is supplied and the optional `basePath` is not
✓ reports nothing once `items` is supplied
✓ does not report the optional props the renderer defaults
 Tests  3 failed | 20 passed (23)

blast radius(这是收紧,必须写清)

今天省略 itemsnavigation-renderer 的 schema,会新增一条 error 级
missing-required-prop(message 形如 < navigation-renderer > is missing required prop "items")。

验证

  • pnpm --workspace-concurrency=2 --filter '@object-ui/layout^...' build(新树先建依赖)
  • 仓根 pnpm exec vitest run packages/layout packages/sdui-parser examples/schema-catalog --maxWorkers=2
    16 files / 1226 tests passed
  • 仓根 pnpm exec turbo run type-check --concurrency=278 successful, 78 total
  • node scripts/check-control-bytes.mjs → OK(3903 tracked text files);改动文件另做了
    一次 grep -naP 控制字节自扫,干净
  • pnpm exec eslint(改动的三个文件)→ 0 errors(index.ts 上两条 warning 是既有的,
    与本改动无关)

第二个 commit 只改注释:上一版把对照写成"两个节点都省略了 basePath",而上一条测试的第二个
节点其实供了它(两者都零诊断)—— 注释真实性正是这条改动在管的事,顺手改准;
examples/schema-catalog 重跑 4 files / 1093 tests passed。

边界

只动 packages/layout/src/index.ts(一行 + 注释)、两个测试文件、一个 changeset
(@object-ui/layout patch,正文写明 blast radius)。未动 NavigationRenderer.tsx 本体,
未碰 content/docs/releases/,未碰同批在飞的 schemas/scripts/fields/app-shell 面。

`NavigationRendererProps.items` 是非可选的 `NavigationItem[]`,渲染器不给默认值,
而注册声明一直没写 `required`。`sdui-parser` 只在 `input.required` 为真时报
`missing-required-prop`(validate.ts:55-64),于是 `{ "type": "navigation-renderer" }`
校验零诊断、渲染直接抛。

运行期实测(非静态读出):第一处无守卫的读点是 `pinnedItems` memo 里的
`collectPinnedItems(filteredItems)`(NavigationRenderer.tsx:1242 → :1410 的
`for (const item of items)`),抛 `TypeError: items is not iterable`。
`resolveActiveNavItem` memo 挡得住(`visit` 首行 `if (!nodes) return`),
:1247 的 `filteredItems.slice()` 同样会抛但走不到。

这是 #3972(键的存在 × 类型)的第四面:可选性。与 #3900/#3972 相反,它是收紧 ——
新增一条 error 级诊断,而被它拦下的形状恰好等于渲染必然崩溃的形状。

钉子两方向 + 对照:
- 注册级(packages/layout):`items.required === true`(两个 namespace);
  `basePath.required` 保持 falsy(渲染器真给了 `basePath = ''` 默认值);
  编译期镜像 `undefined extends items` 为假;运行期崩溃见证。
- 端到端(examples/schema-catalog,与 #3972 的 manifest 门钉同处):省略 items 报
  error 级 `missing-required-prop`;提供数组零诊断;可选属性省略不报。
- #3900 的 `not-a-container` 对照节点补 `items: []`,恢复单一事实(注释同步)。

Fixes #3987

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
@vercel

vercel Bot commented Aug 9, 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 9, 2026 10:28pm

Request Review

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

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

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 8.66KB 3.13KB
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.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
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) 26.07KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.65KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 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) 483.62KB 106.67KB
core (index.js) 3.00KB 1.14KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 139.61KB 35.99KB
fields (index.js) 227.99KB 56.47KB
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.65KB 1.06KB
i18n (pickLocalized.js) 1.70KB 0.83KB
i18n (provider.js) 9.48KB 3.27KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 4.52KB 1.96KB
layout (index.js) 38.84KB 10.80KB
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.32KB 1.64KB
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) 45.23KB 12.45KB
plugin-charts (index.js) 61.49KB 17.48KB
plugin-chatbot (index.js) 180.33KB 42.79KB
plugin-dashboard (index.js) 118.67KB 30.69KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 237.80KB 59.48KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 112.86KB 27.24KB
plugin-gantt (index.js) 162.79KB 39.67KB
plugin-grid (index.js) 187.97KB 49.79KB
plugin-kanban (index.js) 48.53KB 13.38KB
plugin-list (index.js) 109.73KB 26.55KB
plugin-map (index.js) 17.05KB 5.33KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 40.58KB 10.58KB
plugin-timeline (index.js) 25.99KB 7.42KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.03KB 20.55KB
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) 23.71KB 7.95KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.23KB 0.66KB
react (spec-input.js) 0.20KB 0.18KB
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.71KB 1.34KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
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

上一版写成"两个节点都省略了 basePath",而上一条测试的第二个节点其实供了它
(两者都零诊断)。注释真实性是这条改动本身在管的事,顺手改准。

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

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

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

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 8.66KB 3.13KB
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.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
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) 26.07KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.65KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 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) 483.62KB 106.67KB
core (index.js) 3.00KB 1.14KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 139.61KB 35.99KB
fields (index.js) 227.99KB 56.47KB
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.65KB 1.06KB
i18n (pickLocalized.js) 1.70KB 0.83KB
i18n (provider.js) 9.48KB 3.27KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 4.52KB 1.96KB
layout (index.js) 38.84KB 10.80KB
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.32KB 1.64KB
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) 45.23KB 12.45KB
plugin-charts (index.js) 61.49KB 17.48KB
plugin-chatbot (index.js) 180.33KB 42.79KB
plugin-dashboard (index.js) 118.67KB 30.69KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 237.80KB 59.48KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 112.86KB 27.24KB
plugin-gantt (index.js) 162.79KB 39.67KB
plugin-grid (index.js) 187.97KB 49.79KB
plugin-kanban (index.js) 48.53KB 13.38KB
plugin-list (index.js) 109.73KB 26.55KB
plugin-map (index.js) 17.05KB 5.33KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 40.58KB 10.58KB
plugin-timeline (index.js) 25.99KB 7.42KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.03KB 20.55KB
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) 23.71KB 7.95KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.23KB 0.66KB
react (spec-input.js) 0.20KB 0.18KB
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.71KB 1.34KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
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

Copy link
Copy Markdown
Collaborator Author

PM 验收(session_01GTRjn8xBqp75dk7kFupVRt):通过,转 ready 并挂 auto-merge。#3987 落地 —— navigation-renderer 声明面四连修(#3900 isContainer / #3972 icon+actions+items 类型 / 本单 required)收口。

核验记录(head 1364d5c2c,基 0cbdca888,实物核验 + CI 亲读):

  1. 一行收紧 + 运行期见证:required: true 落地(实物 grep);崩溃从静态读出升级为实测复现(TypeError: items is not iterable @ collectPinnedItems),且细化了 issue 锚点(:1242 pinnedItems memo 先崩,:1247 走不到;:1229 反而挡得住)—— 前提核验做成了更准的事实。
  2. 常驻见证钉带未来处置指引:运行期崩溃钉入库并在文件头写明「若将来采 = [] 默认值路线应替换为空导航断言而非删除」—— 防下一个读者直接删记录;V8 文案依赖也已注释。
  3. 编译期镜像钉(undefined extends Props['items'] 为假)+ 注册级双 namespace + 端到端 missing-required-prop(error 级 + 可达性前置)+ 三组对照 —— 层次齐。
  4. fixture triage 正确:packages/layout: page-header 注册缺 isContainer: true,而 PageHeader 有意渲染 schema.children —— sdui-parser 对文档认可的写法报 not-a-container #3900 对照节点补 items: [] 是恢复 fixture 单一事实性,断言按 code 过滤两态皆绿 —— 不是为绿而改。
  5. 反向验证:3 红 20 绿逐条命中,含「运行期见证在变异下保持绿(它是理由不是后果)」的方向自觉。
  6. 门与规程:1226 测试绿;type-check 78/78;控制字节门 + 自扫;changeset patch 且 blast radius(仓外 error 级新诊断 = 必崩形状)写明;fable 0;消费半径扫描在案。
  7. CI 亲读终态:20/20 全 completed、0 失败(Test shard×4 至 22:35:08Z)。

out-of-scope #3999(layout README 的 SidebarNav 示例三键全错 + side-effects 注释旁证)由 PM 分诊(另评)。


Generated by Claude Code

@yinlianghui
yinlianghui marked this pull request as ready for review August 9, 2026 22:59
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 9, 2026
Merged via the queue into main with commit f3b2874 Aug 9, 2026
21 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-3987-navigation-items-required branch August 9, 2026 23:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants