Repository navigation
finding(console): metadata-admin's 172,651 B eager closure is held by a REGISTRY CONTRACT, not by chunking — registerAppComponent takes a component value #6776
Description
Found while implementing objectui#6681, which measured all four of AppContent's
non-single-file lazy() surfaces and freed the two that were removable. This records the
one that was NOT, so the 172,651 B does not leave the backlog when objectui#6681 closes.
Filed unassigned, recording only. Observational: nothing is broken and
pnpm check:eager-closure PASSES (3171.5 KB of a 3222.7 KB ceiling after objectui#6681).
What was measured
On b98352a15, from apps/console/dist/eager-closure.json (files[] IS the eager set)
and the emitted chunks' own module lists — never a source-level search (objectui#6680).
assets/metadata-admin-*.js is 172,651 B gzipped, 144 modules, EAGER — 5.4% of the
whole console eager closure and more than three times its 51.1 KB of headroom. Every
console page load pays for it while AppContent declares its six pages lazy().
The chunk is not held by co-tenancy, which is what objectui#6681 repaired for the
marketplace routes. It is held by real static edges into
packages/app-shell/src/views/metadata-admin/index.ts, the module all six declarations
target:
| eager importer | what it takes | why it is eager |
|---|---|---|
packages/app-shell/src/index.ts |
eleven runtime values re-exported (registerMetadataPreview, useMetadataClient, getMetadataInspector, …) |
the package barrel; the console entry imports it |
packages/app-shell/src/services/builtinComponents.tsx |
MetadataDirectoryPage, MetadataResourceRouter by value, plus PackagesPage and PermissionMatrixEditPage |
the barrel BARE-imports it (import './services/builtinComponents.js';) for its ComponentRegistry registrations |
Decisive for anyone reaching for a chunking lever first: the six pages the declarations
name (DirectoryPage, StudioHomePage, ResourceListPage, ResourceEditPage,
ResourceHistoryPage, DiagnosticsPage) have dynamicImporters: [] in the emitted
module graph. They are reached only through the barrel's static re-exports, so no
advancedChunks group separates them from it — grouping them would emit one eager chunk
instead of one eager chunk. objectui#6681 measured that failure mode directly on the
marketplace pages and recorded it in apps/console/vite.config.ts.
Why it is a registry contract, not a bundling problem
registerAppComponent({ ref, component }) takes a component value, so
builtinComponents.tsx must have loaded the page before it can register the ref. That is
the load-bearing half: the registration itself must happen at module load, or
ComponentNavView cannot resolve metadata:directory when the first
component/... route mounts.
What is NOT load-bearing is that the value be an eagerly-imported component.
React.lazy(() => import('../views/metadata-admin/index.js').then(m => ({ default: m.MetadataDirectoryPage })))
is also a component type. Whether that is correct depends on two things this card does not
settle:
- whether every render site of a registry component sits inside a
<Suspense>boundary
(ComponentNavViewand any host embedding the registry); - whether the package barrel should go on re-exporting eleven runtime values from a
module its ownsideEffectsarray declares side-effectful — those re-exports are a
published API with out-of-package consumers, and they alone keep the module eager even
ifbuiltinComponents.tsxis fixed.
Both are published-contract decisions rather than in-lane bundling changes, which is why
objectui#6681 pinned the surface instead of attempting it.
What this card does NOT claim
- Not a budget regression. The closure PASSES, with more headroom than before
objectui#6681. - Not that the five top-level registrations in
views/metadata-admin/index.ts
(registerBuiltinAnchors,registerDefaultMetadataSchemas,registerDatasourceResource,
registerBuiltinPreviews,registerBuiltinInspectors) should be deleted or declared
side-effect-free. They are load-bearing,@object-ui/app-shell'ssideEffectsarray
names the module for exactly that reason, and objectui#6681 added a guard in
scripts/vite-declared-lazy-views.tsthat refuses to declare it pure — proved to fire
by ablation.
Suggested shape, if graded
Decide (1) and (2) above first; they are the card. If both answers allow it, measure what
a lazy registerAppComponent value plus a leaf-module re-export path is worth, and delete
the views/metadata-admin/index.ts line from DECLARED_LAZY_VIEWS_STILL_EAGER — the
ledger's missing half fails the build until that line goes, so the win cannot be taken
silently.
Related
- objectui#6681 — the card this was found under; the measurement, and the two chunks that
WERE freed. - objectui#6680 — chunk co-tenancy: the mechanism that held the marketplace routes and
explicitly does NOT hold this one. - objectui#6683 / objectui#6735 — the
sideEffectsarray that names this module. - objectui#5324 / objectui#5924 / objectui#6631 — the eager-closure budget and its
headroom.
Activity
claude commentedon Aug 29, 2026
Result: this needs a ruling. Nothing landed, no PR. Here is the analysis, with the price.
Measured on
c6732825d(the commit this card names). Three console builds, each read fromapps/console/dist/eager-closure.jsonand the emitted chunks' own module lists — never asource-level search.
Baseline, from the gate's own verdict line:
assets/metadata-admin-*.js= 172,660 B gzipped, 144 modules, EAGER — the card's 172,651reproduces to within 9 bytes.
1. The render-site census — question 1 is already answered by shipped code
There is exactly one resolver of a
registerAppComponentvalue in the repo:ComponentNavView.tsx:35(getAppComponent(ref)), rendered at line 60. Nothing else callsgetAppComponentorlistAppComponentsto render.ComponentNavViewhas two mount sites:AppContent.tsx:1013, thecomponent/:ns/:name/*routeSuspense fallback=LoadingScreenboundary spanning lines 956-1041 (verified by line number, not by eye)PackagedAutomationPage.navContribution.test.tsx:77await screen.findByRole(...), an async queryA third site renders a registered entry without
ComponentNavView:apps/console/src/__tests__/approvalsInboxComponentRef.test.tsx:97. It tolerates pending too(
await screen.findByTestId) — and it must, because the ref it tests is already lazy.Ten refs are registered today. Five are already lazy, and have shipped:
account:profile_cardregisterAccountComponents.tsx:46Suspense, inside the registered valueapprovals:inboxregisterApprovalsComponents.tsx:58Suspensedeveloper:api-consoleregisterDeveloperComponents.tsx:37Suspensedeveloper:flow-runsregisterDeveloperComponents.tsx:48Suspensedeveloper:public-formsregisterDeveloperComponents.tsx:59Suspensemetadata:directorybuiltinComponents.tsx:36metadata:resourcebuiltinComponents.tsx:43developer:packagesbuiltinComponents.tsx:50automation:packagedbuiltinComponents.tsx:64studio:builderregisterStudioComponents.tsx:58Answer to question 1: no ruling needed. Every render site already tolerates a pending
component, and the established pattern puts the boundary inside the registered value, so
registerAppComponent's signature never changes and no render site changes either. Theregistry contract already admits lazy components; half its entries are lazy.
2. The census the card did not ask for — and it decides the outcome
views/metadata-admin/index.ts's five load-time registrations feed four registries, andthose registries have consumers outside metadata-admin that this card does not name:
views/studio-design/StudioDesignSurface.tsxgetMetadataPreviewx2,getMetadataInspectorx3,getMetadataDefaultInspectorx1index-*.jsisEditable = !!Preview && !StudioCanvas-> canvas silently non-editableviews/studio-design/ObjectSettingsPanel.tsx:75getMetadataDefaultInspector('object')index-*.jsviews/studio-design/ObjectHooksPanel.tsx:88getMetadataDefaultInspector('hook')index-*.jsviews/studio-design/ObjectActionsPanel.tsx:101getMetadataDefaultInspector('action')index-*.jsapps/console/src/preview-gallery.tsxgetMetadataPreview,listMetadataPreviewTypes,getMetadataInspectorpreview-gallery.htmlentryThese reads are synchronous and return
undefined. NoSuspenseboundary can repair anyof them — Suspense catches a promise thrown by a rendering lazy component; it cannot catch
a registry lookup that returns nothing. The failure is silent, exit-0, and renders as
"this surface just isn't editable".
That matters because of where the bytes are. The chunk's 1,219,615 B rendered, by subtree:
previews/*inspectors/*metadata-admin/*top level (incl. all six declared-lazy pages)external/*datasource/*The six pages the card names total 147,777 B rendered = 12.1%. The previews and
inspectors held by those four eager
studio-designconsumers are 66.8%.3. What it is actually worth — measured, not argued
c6732825dbuiltinComponents.tsx, package barrel untouchedmetadata-adminchunk grew +189 B (thelazy/Suspense/fallback code) and stayed EAGER. No chunk left or joined; 45/513 unchanged.views/metadata-admin/register-builtins.tsbare-imported by the package entry, lazy registration,sideEffectsarray entry swapped, ledger pin deletedE1b in detail:
metadata-admin(172,660) leaves the eager closure entirely and becomes lazy —but
srcgrows +128,647 and four chunks join (SchemaForm28,083,ActionResultDialog12,767,
useMonacoFallback9,705,nav-selection592). 877,242 B of previews andinspectors stay EAGER, relocated into
src-*.js, held byregister-builtins.ts(240 B,eager) which the package entry must bare-import for the four
studio-designconsumers above.So the contract change both questions gate is worth 31.0 KB, not 172.7 KB. The remaining
~141 KB is held by a different contract — the preview/inspector registries — whose failure
mode is a silent
undefined, not a pending component.Two things only an attempt could have found
failed:
declared-lazy-viewsrefuses to declare a view side-effect-free when it carries abare side-effect import, so
import './register-builtins.js';insideviews/metadata-admin/index.tskeeps the page barrel unshakeable and the win is zero. Theregistrations must hang off the package entry. That is safe here only because
@object-ui/app-shell'sexportsmap is root-only (.and./styles.css), so noconsumer can deep-import the page barrel and observe the move — verified, not assumed.
Rolldown's
INEFFECTIVE_DYNAMIC_IMPORTfires when one module both statically anddynamically imports a specifier; here the static edge lives in a different module
(
packages/app-shell/src/index.ts), so nothing warns. E2 is objectui#5486's exact shape —a
lazy()claiming a split it does not have — and it would have landed green and silent.4. Why I stopped
The 31.0 KB requires editing
packages/app-shell/src/index.tsandpackages/app-shell/package.json'ssideEffectsarray. Both are outside this card's filesurface, and the second is a published-contract field established by the maintainer ruling of
2026-08-29 (objectui#6683). Changing where the load-time registrations live is question 2.
So it is reported, not taken.
In every arm below,
registerAppComponent's signature is unchanged and the barrel's publicexport names and types are unchanged.
Arm A — do nothing. 172,660 B stays eager. Zero risk. The gate passes today with 48.6 KB
of headroom.
Arm B — take the 31.0 KB (E1b, measured green). Risk is confined to the⚠️ Implementation note: -31.0 KB takes aggregate headroom from 48.6 KB
sideEffectsarray and the registration locus; the root-only
exportsmap makes the move unobservableoutside the package.
to 79.7 KB, i.e. 0.55x -> 0.89x of the 89.0 KB regression the gate exists to catch. Still
under the 1.0x error threshold, but close enough that the ceiling should be re-baselined in
the same change or the gauge starts going blind.
Arm C — go after the ~141 KB where it actually is. That means the eager
views/studio-design/surface, not the ComponentRegistry. It is a distinct question with adistinct failure mode (silent
undefined, not pending component), andregisterStudioComponents.tsx's own docblock already rules the studio surface's laziness "aseparate measured card, not a rider here".
Recommendation: B now, C as its own card. B is measured, green, and preserves every name
and type; C is where two thirds of the bytes are but needs its own measurement and its own
answer about unpopulated registries. Question 1 needs no ruling at all.
Verification artifacts: three console builds under the shared verify lock, each exiting 0
(
os-verify-lock: VERDICT command-exit 0), budget gateexit=0with the verdict line quotedabove. Working tree reset to
c6732825dand confirmed byte-identical (git diff --quiet=clean); nothing landed on
claude/issue-6776-metadata-admin-registry-contract.Out-of-scope finding filed: objectui#6785.
Generated by Claude Code
Generated by Claude Code
claude commentedon Aug 29, 2026
os-dev-report
{ "issue": 6776, "status": "needs_decision", "branch": "claude/issue-6776-metadata-admin-registry-contract", "pr": null, "premise_still_valid": true, "summary": "Premise holds and reproduces: on c6732825d, assets/metadata-admin-*.js is 172,660 B gzipped / 144 modules / EAGER (the card's 172,651 to within 9 bytes), held by exactly the two static edges the card names. Nothing landed and no PR was opened, because the only reduction with a measurable value requires editing packages/app-shell/src/index.ts and packages/app-shell/package.json's sideEffects array -- both outside this card's file surface, and the second IS contract question 2. Full census + numbers posted to the card: https://github.com/objectstack-ai/objectui/issues/6776#issuecomment-5462673629 . THREE RESULTS. (1) Contract question 1 needs no ruling: there is exactly one resolver of a registerAppComponent value (ComponentNavView.tsx:35), it has two mount sites and BOTH already tolerate a pending component (AppContent.tsx:1013 sits inside the Suspense boundary spanning 956-1041; the test site asserts through await findByRole), and 5 of the 10 registered refs are ALREADY lazy in shipped console code, each carrying its own Suspense boundary INSIDE the registered value -- so the signature never changes and no render site changes. (2) The card asks about the wrong failure mode for most of the bytes. The five load-time registrations also feed FOUR EAGER views/studio-design/ consumers (StudioDesignSurface, ObjectSettingsPanel, ObjectHooksPanel, ObjectActionsPanel) that read the preview/inspector registries SYNCHRONOUSLY and degrade silently on undefined (isEditable = !!Preview). No Suspense boundary can repair a lookup that returns undefined. Those registries are 66.8% of the chunk; the six declared-lazy pages the card names are 12.1%. (3) Priced it: the full contract-changing shape is worth -31,794 B gzipped, NOT -172,651. The in-fence-only change is worth -30 B and leaves the chunk eager. CORRECTION to a detail carried by both the card body and the DECLARED_LAZY_VIEWS_STILL_EAGER docblock: the barrel re-exports 25 RUNTIME values (each a static edge) plus 11 TYPE-ONLY values (erased, no edge) -- 'eleven runtime values' counted the type block. Filed as #6785. Working tree reset to c6732825d and confirmed byte-identical; the pushed branch is empty.", "tests": "No source change was landed, so no gate is owed on a diff -- the working tree is byte-identical to c6732825d (git diff --quiet against BASE = clean, git status clean, HEAD=c6732825d). Note objectui has no scripts/pm/dispatch-gates.mjs (that script lives in objectstack and answers only about its own tree), and the diff here is empty either way. MEASUREMENT RUNS -- three console builds, all under the shared verify lock, all exiting 0 ('os-verify-lock: VERDICT command-exit 0', held 169s / 77s / 86s / 83s), each read from apps/console/dist/eager-closure.json and the emitted chunks' own module lists via dist/stats.html: [E0 baseline c6732825d] eager 3,250,187 B gz, 45/513 chunks; metadata-admin 172,660 B gz / 144 modules. Budget gate run over that artifact, exit=0, its own verdict line: 'Console eager closure is 3174.0 KB gzipped across 45 of 513 chunks (budget: 3222.7 KB, headroom: 48.6 KB).' [E2 in-fence-only: lazy registration value in builtinComponents.tsx, barrel untouched] eager 3,250,157 B = -30 B; metadata-admin chunk GREW to 172,849 (+189 B, the lazy/Suspense/fallback code) and stayed EAGER; no chunk left or joined, 45/513 unchanged. Rolldown's ineffective-dynamic-import ledger did NOT flag it (stayed '43, all pinned') because the static edge lives in a different module -- so this no-op split would land green and silent. [E1b full shape: 25 runtime + 11 type re-exports repointed to leaves, five registrations lifted to views/metadata-admin/register-builtins.ts bare-imported by the PACKAGE ENTRY, lazy registration, sideEffects array entry swapped, ledger pin deleted] build green, eager 3,218,393 B = -31,794 B (-31.0 KB), 48/517 chunks. metadata-admin (172,660) leaves and becomes lazy; src +128,647 and four chunks join (SchemaForm 28,083, ActionResultDialog 12,767, useMonacoFallback 9,705, nav-selection 592); 877,242 B of previews+inspectors STAY EAGER in src-*.js, held by register-builtins.ts (240 B, eager) which the package entry must bare-import for the four studio-design consumers. NEGATIVE RESULT worth recording: the first E1 attempt FAILED the build -- 'declared-lazy-views refusing to declare packages/app-shell/src/views/metadata-admin/index.ts side-effect-free: it carries a bare side-effect import (import ./register-builtins.js)'. So the registrations cannot hang off the page barrel; they must hang off the package entry. That is safe only because @object-ui/app-shell's exports map is root-only ('.' and './styles.css'), verified from package.json, so no consumer can deep-import the page barrel and observe the move. Each experiment was COMMITTED before measuring (restore points 0e1c1a460 / 844ab0fec / ffc31154b), then reverted with git reset --hard to BASE and the revert PROVEN by git diff --quiet against BASE returning clean -- not by a checkout exit code. The E1b diff is preserved at scratchpad issue-6776/E1b.patch (236 lines) so the ruling can be implemented from a measured patch.", "mcp_calls": "0 -- the whole run used repo-scoped REST over curl (probe returned 200); /search/* is 403 by egress design, so dedup used repo-scoped list endpoints + local grep over 244 open issues with #6776 itself as the positive control", "open_questions": [ { "question": "Q1 (the card's first contract question) -- does every registry render site tolerate a pending component, i.e. is Suspense coverage sufficient for a lazy registerAppComponent value?", "options": [ "A. Needs a ruling / needs Suspense work before laziness is safe.", "B. Already satisfied -- no ruling and no render-site change needed." ], "recommendation": "B, and this one is settled by measurement, not judgement. One resolver (ComponentNavView.tsx:35), two mount sites, both already tolerant: AppContent.tsx:1013 is inside the Suspense boundary spanning 956-1041, and the test mount asserts via await findByRole. Decisively, 5 of the 10 registered refs are ALREADY lazy in shipped console code (account:profile_card, approvals:inbox, developer:api-console, developer:flow-runs, developer:public-forms), and each puts its Suspense boundary INSIDE the registered value -- so the boundary travels with the component, registerAppComponent's signature is untouched, and no render site is asked to tolerate anything new. The registry contract already admits lazy components; half its entries are lazy today." }, { "question": "Q2 (the card's second contract question) -- should the package barrel go on re-exporting runtime values from a module its own sideEffects array declares side-effectful? Answering it costs edits to packages/app-shell/src/index.ts and packages/app-shell/package.json, both outside this card's file surface, and it is worth a measured -31,794 B (not -172,651).", "options": [ "A. Leave it. 172,660 B stays eager; zero risk; the gate passes today with 48.6 KB headroom.", "B. Take the 31.0 KB (E1b, already measured green): repoint the 25 runtime + 11 type re-exports to leaf modules (same NAMES, same TYPES), lift the five registrations into views/metadata-admin/register-builtins.ts bare-imported by the PACKAGE ENTRY, register metadata:directory / metadata:resource as lazy values with their own Suspense, swap the sideEffects array entry, delete the ledger pin.", "C. Go after the ~141 KB where it actually is -- the eager views/studio-design/ surface -- as its own card." ], "recommendation": "B now, C as its own card, A only if the sideEffects array is considered frozen. Four axes. REAL BUSINESS NEED: real but modest, and I measured it rather than assuming -- 31.0 KB off every console page load, 0.98% of a 3174.0 KB closure with 48.6 KB of headroom. It is NOT the 172.7 KB the card implies, and anyone deciding on that number would be overpaying for the risk. LONG-TERM SOUNDNESS: B is the contract-first shape. The five registrations are load-bearing platform state; today they are an accident of which barrel happens to be imported, and B makes them an explicit edge from the package entry -- the thing that is true becomes the thing that is declared. It also leaves the sideEffects array MORE honest, not less: the array is derived, and after B it names the module that actually registers. AI-WRITTEN-CODE SAFETY: this is the axis that decides B over a broader change. The four eager studio-design consumers read the preview/inspector registries synchronously and fail SILENTLY on undefined (isEditable = !!Preview) -- exactly the fail-open shape this project refuses. B keeps those registrations eager and their consumers correct by construction, and it does so through the package entry rather than through an implicit chain nobody can see. Any arm that makes previews and inspectors lazy without first fixing that read is the dangerous one, which is why C must be measured separately rather than ridden along. STARTUP SCOPE DISCIPLINE: B adds no capability and no new surface -- one new leaf module, zero new exported names, zero new API. C is deliberately deferred rather than bundled, matching registerStudioComponents.tsx's own docblock, which already rules the studio surface's laziness 'a separate measured card, not a rider here'. IMPLEMENTATION NOTE if B is taken: -31.0 KB moves aggregate headroom 48.6 -> 79.7 KB, i.e. 0.55x -> 0.89x of the 89.0 KB regression the gate exists to catch. Under the 1.0x error threshold but close, so re-baseline MAX_EAGER_CLOSURE_GZIP_BYTES in the same change or the gauge starts going blind." } ], "out_of_scope_findings": [ "filed as #6785: DECLARED_LAZY_VIEWS_STILL_EAGER's metadata-admin docblock says the barrel re-exports 'eleven runtime values'; the runtime block has 25 (each a static edge) and 11 is the TYPE-ONLY block beneath it (erased at build, zero edges) -- the error already propagated verbatim into #6776's body, pointing any implementer at the one block that provably holds nothing eager", "not filed, recorded here as it is inseparable from this card: builtinComponents.tsx holds two MORE by-value component registrations that keep bytes eager through a SECOND registry -- registerMetadataResource({ type: 'permission', EditPage: PermissionMatrixEditPage }) pins PermissionMatrixEditor.tsx (36,101 B rendered, eager) and registerAppComponent('developer:packages') pins PackagesPage.tsx (30,801 B rendered, eager). Both survive E1b untouched. If PM wants them chased, they are the same contract shape as this card and belong on it or on its successor, not on a separate card" ] }Generated by Claude Code
claude commentedon Aug 29, 2026
Claim:
domain:uiexecution seat · PM sessionsession_01CRJge11jso9TpXRWFt1Z49· round R13 · branchclaude/issue-6776-metadata-admin-registry-contractWhy this is not merely tidiness. The seat-mutex protocol's fourth read resolves who holds a lane from the
Claim:session ID on the lane's most recently updated closed card. With no marker on these cards, this session was invisible to that read and indistinguishable from an empty seat — a sibling session performing the open-round mutex check could have concluded the lane was free and taken it while it was occupied.Cause, recorded rather than excused. The markers were skipped while rushing the round after being asked why nothing had been dispatched. Claiming is the step that must not be dropped under time pressure, because it is the only one another session can see.
Outcome: still in flight — branch still on the remote.
Generated by Claude Code
claude commentedon Aug 29, 2026
状态更正:
pm:dispatched→needs-user-decision本卡的派发以
needs_decision收场 —— 没有 PR,分支上什么都没落,工作树已复位并确认git diff --quiet干净。那么pm:dispatched就是个半状态:它对在飞查询说「有人在做」,而实际上没有。改挂决策态并补四棱块。⭐ 派发的产出不是零 —— 它把卡里两个问题中的一个直接答掉了,并且推翻了卡自己的价格。
一句话问题:metadata-admin 的 172,660 B eager 闭包要不要变懒 —— 但实测把价格改了:这个契约变更只值 31.0 KB,不是 172.7 KB,余下 ~141 KB 由另一个契约(preview / inspector 注册表)持有,失败模式是静默
undefined而不是 pending 组件。问题 1 不需要裁决(已由已发布代码答掉)。 仓内只有一个
registerAppComponent值的解析点,它的每一个渲染站点都已容忍 pending;十个已注册 ref 里五个本来就是 lazy 并已发版,既有模式把边界放在注册值内部,所以registerAppComponent的签名不变、渲染站点不变。三条臂
sideEffects数组与注册点位置;root-only 的exportsmap 使这次移动在包外不可观测(已验证,非假设)views/studio-design/面,不是 ComponentRegistry。不同的问题、不同的失败模式,已另立卡四棱
① 长远合理性:B 要改两处 —— 把 load-time 注册从页面 barrel 提到包入口,以及
package.json的sideEffects数组,而后者是 2026-08-29(#6683)维护者裁定确立的已发布契约字段。⇒ 这是契约面的决定,不是打包优化,这也正是 dev 停手报告而不是动手的原因。② 业务拉动:⚠️ 今天没有。 门禁通过,余量 48.6 KB。没有人在等这 31 KB。
③ 防 AI 犯错:⭐ 本卡最重要的一条,而且它指向一个反对草率取 B 的理由。看起来最小、最"in-fence"的改法 E2 —— 只在
builtinComponents.tsx里把注册值改成 lazy —— 实测只值 -30 B,chunk 反而涨了 189 B 且仍然 EAGER;而且它会绿着通过所有门禁:ineffective-dynamic-import 台账抓不到它,因为静态边住在另一个模块里。⇒ E2 正是 #5486 的形状——一个lazy()声称了它并不具备的分割。任何后来者(人或 AI)想"顺手做个懒加载"都会写出 E2。无论本卡裁成什么,这个陷阱都应当被写下来。④ 创业阶段不扩散:A 零成本;B 有界但触两处契约面;C 是独立的一张卡,不该并进来。
⭐ 置信缺口(本席未独立复核,诚实列出)
undefined,Suspense 结构上修不了 ⇒ C 不是"再做一次 B"。preview-gallery这个 standalone entry 不在生产构建里,它对 C 的约束有多大。低摩擦裁决:回「A」「B」「B + 同批重设 ceiling」或「先做 C」。
裁后执行:裁 B ⇒ 转
pm:queue,派发令必须点名packages/app-shell/src/index.ts与package.json的sideEffects两处契约面,并把 ceiling 的处置写死。裁 A ⇒ 关卡,但 ⛔ 必须把上面第③条的 E2 陷阱写进builtinComponents.tsx旁的注释并指向本卡 —— 只关不写,下一个人就会落地 E2。Generated by Claude Code
zhuangjianguo commentedon Aug 30, 2026
⚖️ RULED — 维护者,2026-08-30,第 5 场总监席决裁批 #4,verbatim「同意」
裁定:采选项 B(取 31KB)+ 同批重设 eager ceiling;问题 1(渲染站点容忍 pending)已由实测答定、无需裁决;C(去拿 141KB)是 arm C、即 #6795,独立处理。
packages/app-shell/src/index.ts的 barrel 再导出(25 runtime + 11 type,同名同类型重指向 leaf 模块)②packages/app-shell/package.json的sideEffects数组(Should@object-ui/app-shelldeclare asideEffectsfield? Measured at 242.6 KB gzipped — 8x today's console headroom — but it is a published contract whose failure mode is silent #6683 确立的已发布字段);五个 load-time 注册提到views/metadata-admin/register-builtins.ts由包入口 bare-import(⛔ 不能挂页面 barrel,declared-lazy-views 会拒),metadata:directory/metadata:resource注册为 lazy 值带各自 Suspense,删 ledger pin。E1b 已实测构建绿、-31,794 B,root-only exports 使移动包外不可观测(已验证)。MAX_EAGER_CLOSURE_GZIP_BYTES;抬 ceiling 是有申报程序的 ratchet,裁决原话引入 PR 正文。builtinComponents.tsx改 lazy)只值 -30B、chunk 反涨且绿着过所有门禁(ineffective-dynamic-import 台账抓不到,静态边在另一模块),是 apps/console: registerStudioComponents.tsx lazy-imports the @object-ui/app-shell barrel it also statically imports — the laziness is decoration #5486 形状。在builtinComponents.tsx旁注写下该陷阱指向本卡,防后来者「顺手懒加载」。registerAppComponent签名与 barrel 公开导出的名与类型不变。修正 finding(build): DECLARED_LAZY_VIEWS_STILL_EAGER's metadata-admin entry says "eleven runtime values" — the runtime block has 25, and eleven is the TYPE-only block beneath it #6785 已记:barrel 是 25 runtime(各一静态边)+ 11 type-only(擦除无边),原「eleven runtime values」计入了 type 块。性质:B 触已发布
sideEffects契约面 ⇒ 派发按内容判条款②(移动注册点位 + sideEffects 数组变更),档位由 ui 席定;⛔ 治理面(#6683 sideEffects 数组)PR 走人工合并道,不 arm auto-merge。席位边界(裁不派):录裁 + 转pm:queue。同笔摘needs-user-decision。裁决入本场追认摘要表。Generated by Claude Code
zhuangjianguo commentedon Aug 30, 2026
needs:contract-reviewremoved — 执行维护者 2026-08-28 对 objectstack#12887 的裁定(可复审增量存在前永不挂标;预挂已废止)。本卡 dev 在飞、PR 尚未存在,条款② 判定不变(裁决已按内容判命中),PR 存在的同笔即重挂双载体;另注意本卡裁决已指定治理面走人工合并道。⛔ Deliberate removal, not a sanitizer strip — do not re-hang without a reviewable diff. 项目总监席,sessionsession_01DxbNgzPMo4YuRBmGmCQp9m。Generated by Claude Code
perf(app-shell): take metadata-admin out of the console eager closure…
os-litant commentedon Sep 2, 2026
Closed-card label hygiene:
pm:dispatchedstripped from this closed card (completed via PR #6913, merged 2026-08-31) so it stops counting in the lane's in-flight view.domain:uiexecution seat, sessionsession_01NRRumy89BYdW9ogbcdHTho(os-litant); no other change.Generated by Claude Code