Skip to content

console first load: @objectstack/spec arrives as self-contained subpath bundles that duplicate each other; three tiny imports pull /system, /kernel and /api whole into the eager closure #13447

Open

Description

@os-zhuang

维护者速读

生产构建实测:首屏急加载闭包 3,248 KB gzip(78/2,262 个 chunk),其中 vendor-objectstack 一个 chunk 1,578.7 KB gzip = 48.6 %。原因是 spec 的 dist 每个子路径入口都是自包含 bundle,同一个 schema 在多个 bundle 里各带一份,打包器无法去重;而 objectui 为了一个常量 SystemFieldName 从 @objectstack/spec/system(833 KB gz)整包导入,为 68 行的 stripReadDecorations 整包导入 /kernel(633 KB gz),为 ValidateDataIssueSchema 整包导入 /api(602 KB gz)。短期改三处导入即可,长期要 spec 改构建。

Measured (console production build on 2026-10-24, HEAD 7981384, spec pin 915e9404)

  • apps/console/dist/eager-closure.json: 78 eager chunks of 2,262, 3,326,131 bytes gzipped; pnpm check:eager-closure passes at 3248.2 KB against the 3744.1 KB ceiling. Largest eager chunks (gz KB): vendor-objectstack 1578.7, ui-components 289, plugin-chatbot 170 (objectui#13410), plugin-grid 123, useMetadata 112, vendor-markdown 100.
  • The pinned spec dist (node_modules/.cache/objectstack/spec/dist) ships 24 JS files, 9.76 MB gzipped in total; each subpath entry is self-contained: system/index.mjs 833 KB gz, index.mjs 826, kernel/index.mjs 633, api/index.mjs 602, shared/index.mjs 446, data/index.mjs 438, ui/index.mjs 412, automation/index.mjs 147.
  • Duplication is real, not inferred: grep -l "FieldSchema = " dist/index.mjs dist/*/index.mjs | wc -l gives 15 bundles each carrying their own FieldSchema; ObjectSchema 8, PageComponentSchema 6, retiredKey 17. Different module ids, so rolldown keeps every copy.
  • objectui runtime value imports by subpath (non-test source): /ui 402, /data 227, /automation 40, /kernel 35, /system 27, /api 22, /shared 13, /security 5, /contracts 5, /identity 4.
  • The eager pulls: packages/permissions/src/MePermissionsProvider.tsx and packages/plugin-list/src/ListView.tsx both import { SystemFieldName } from '@objectstack/spec/system' while data/index.mjs (already eager) exports the same constant; packages/app-shell/src/services/MetadataService.ts and packages/data-objectstack/src/index.ts import stripReadDecorations from @objectstack/spec/kernel (the only exporter; the function is 68 lines in spec/src/kernel/metadata-read-decorations.ts); packages/data-objectstack/src/index.ts imports ValidateDataIssueSchema from @objectstack/spec/api (only exporter).

Recommendation

  • (S, objectui) Point the two SystemFieldName imports at @objectstack/spec/data; rebuild and read eager-closure.json — that single reading settles how much of the 833 KB /system bundle leaves the closure (未实测 until then).
  • (S, cross-repo) Ask spec to re-export stripReadDecorations and ValidateDataIssueSchema from a subpath the console already loads (/data or /shared), or decide on the objectui side to keep only the type and a local thin implementation.
  • (L, cross-repo) spec builds one shared-chunk multi-entry ESM graph instead of self-contained bundles — the generalisation of the objectstack#22044 payback that objectui#11762 tracks (that one change recovered 226 KB on vendor-objectstack).
  • Then lower MAX_EAGER_CLOSURE_GZIP_BYTES and re-pin BASELINE in scripts/check-eager-closure-budget.mjs by the measured amount, per objectui#11762's rule.

Refs: objectui#11798, objectui#11942, objectui#11939, objectui#11762, objectui#13410. None of them names the subpath duplication or these three pulls.

Filed by the read-only whole-repo review session https://claude.ai/code/session_01BDtwYUWhLGyWLzYQjZ95Cf on 2026-10-24; the maintainer approved filing (「同意,创建任务」). Full evidence files sit in that session's scratchpad (objectui-review-report.md, findings-*.md). ⛔ Not a claim; for triage to grade and route.


Generated by Claude Code

Activity

  1. added
    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 24, 2026
  2. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    enhancementNew feature or request
    and removed
    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
    on Oct 24, 2026
  3. objectstack-fleet commented on Oct 24, 2026

    @objectstack-fleet
    Contributor

    Triage: first grade — enhancement · priority:p2 · domain:ui · area:records · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-24T15:04Z

    ⛔ Not a claim, ⛔ not a dispatch. finding comes off. domain:spec comes off: one lane per card.

    • This card: the objectui half. Repoint the two SystemFieldName imports at @objectstack/spec/data, rebuild, and read eager-closure.json. Then lower MAX_EAGER_CLOSURE_GZIP_BYTES by the measured amount (objectui#11762's rule).
    • The objectstack half (re-export stripReadDecorations and ValidateDataIssueSchema from a loaded subpath; spec's shared-chunk ESM build, L) is objectstack's domain:spec work. It is filed there once the objectui reading gives the number.

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1 · 2026-10-25T02:07Z
    Session: session_01DRkSLfTy6PpiFqHxtNBjSa (the card session that works this card; claim written by the domain:ui seat 4 session session_01XWGTsmqrtrt1Zqh1ioWqsT)
    Account: os-elon-musk
    Branch: claude/project-thread-wqfjll (platform-assigned at spawn; the card session can push only this branch)
    Worktree: objectui-issue-13447
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: the SystemFieldName import line in packages/permissions/src/MePermissionsProvider.tsx and in packages/plugin-list/src/ListView.tsx (that line only); MAX_EAGER_CLOSURE_GZIP_BYTES / BASELINE in scripts/check-eager-closure-budget.mjs and the tests that pin them (scripts/__tests__/check-eager-closure-budget.test.ts, scripts/__tests__/ci-cd-pipeline-doc.test.ts) and the doc line they read; .changeset/13447-*.md if a published package changes (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default tier (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: 6385771626
    Premise: holds — on objectui main c85408f MePermissionsProvider.tsx:23 and ListView.tsx:48 import SystemFieldName from @objectstack/spec/system; the ceiling is MAX_EAGER_CLOSURE_GZIP_BYTES = 3_579_945 at check-eager-closure-budget.mjs:1371
    Serial constraints cleared: ListView.tsx is in seat 1's objectui#13442 surface (its PR #13474 does not touch the file at this reading) and in seat 4's PR #13486 (in the merge queue; it edits the @object-ui/core and @objectstack/spec/ui import lines, not line 48) — this card edits one other import line; merge main before opening and again before landing
    Writes: all PR, comment and label writes go only through objectstack's relay (scripts/pm/fleet-write); never write with GitHub MCP.

    • Ruling section: maintainer approved filing (「同意,创建任务」); triage 6385771626: this card is the objectui half only — repoint the two imports, rebuild, read apps/console/dist/eager-closure.json, then lower the ceiling by the measured amount (objectui#11762's rule).
    • Measure, then write: the PR body states the before/after eager-closure readings (gz bytes and the vendor-objectstack chunk) from a real production build on the same machine. If the repoint saves nothing measurable, do not lower the ceiling; report the reading and stop.
    • Out of scope: the objectstack half (re-export stripReadDecorations / ValidateDataIssueSchema from a loaded subpath; spec's shared-chunk ESM build). The seat passes the measured number to objectstack's domain:spec lane after landing; the dev files nothing there.
  5. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 13447,
      "status": "done",
      "branch": "claude/project-thread-wqfjll",
      "pr": null,
      "session": "session_01DRkSLfTy6PpiFqHxtNBjSa",
      "premise_still_valid": false,
      "summary": "Premise falsified twice; no code change and no PR, per the claim's 'if it saves nothing, don't touch the ceiling; report the readings and stop'. (1) `@objectstack/spec/data` does not export `SystemFieldName`: the constant is declared in packages/spec/src/system/constants/system-names.ts and data/index.ts re-exports nothing by that name at e649c2d9 (objectui's pin), 915e9404 (the card's pin) or objectstack origin/main 25f88e8. The `SystemFieldName = {` the card found in dist/data/index.mjs is a bundled private copy used by data's own injected-system-column code, not an export. Runtime, from packages/permissions: `'SystemFieldName' in await import('@objectstack/spec/data')` = false, `/system` = true, root `@objectstack/spec` = false; dist/data/index.d.ts has zero mentions. So the claimed one-line repoint would fail type-check and resolve to undefined. (2) Even taken off /system, the two imports pull nothing that is not already eager: an uncommitted experiment build that replaced both imports with a local `{ OWNER_ID: 'owner_id' }` literal moved the eager closure by +382 bytes gzipped, not down. The /system code stays in vendor-objectstack because other eager modules import /system values (FlowRunner, flowResponse, metadata-form-i18n, packages/types nested-component-walk are the candidates; not attributed below the chunk), and rolldown tree-shakes the self-contained subpath bundle, so the 833 KB whole-bundle figure is not what lands (the system-only marker strings 'Vector clock' and 'Backup retention' are absent from the eager chunks of the main build; 'Log destination' is present).",
      "tests": "Two console production builds, same container, same instrument, each `CI=true NODE_OPTIONS=--max-old-space-size=6144 pnpm exec turbo run build --filter=@object-ui/console... --concurrency=2` under scripts/pm/os-verify-lock.sh (VERDICT command-exit 0 both; 35/35 tasks), reading apps/console/dist/eager-closure.json. Control = main c85408f: 3,086,819 bytes gz across 85 of 2291 chunks, vendor-objectstack 1,622,904. Experiment = c85408f plus the two imports swapped for a local literal (uncommitted; on-disk proof: marker grep 1 and old import grep 0 in both files before the build; restored by trap with `git checkout HEAD --`, `git diff HEAD` empty after): 3,087,201 across 85 of 2291, vendor-objectstack 1,623,222. Delta: aggregate +382, vendor-objectstack +318, ui-components -52, every other chunk name within +-10. No test suites run: nothing committed.",
      "gates": "n/a: no diff, no commit, no PR. `pnpm check:eager-closure` not re-run; the ceiling and BASELINE are untouched as the claim directs for a zero saving.",
      "dogfood_battery": "n/a: no PR",
      "mcp_calls": "2: mcp__github__issue_read get and get_comments on objectui#13447 (read-only; no write tool)",
      "api_writes": "1: this os-dev-report comment via the fleet-write relay (POST issues/13447/comments)",
      "open_questions": [
        {
          "question": "Does the /system part of the card survive at all, and if so where?",
          "options": [
            "A: close the SystemFieldName item as measured zero; move the first-load effort to the objectstack domain:spec half (shared-chunk multi-entry ESM build), which is what actually decides vendor-objectstack's size",
            "B: ask spec to re-export SystemFieldName from /data anyway (tidiness only; measured saving 0)",
            "C: before either, have someone attribute which eager modules keep /system in vendor-objectstack (a module-level dump of the console build), so the /system share is a number rather than a candidate list"
          ],
          "recommendation": "C then A: the experiment shows these two imports are not the lever, and the card's 833 KB is a whole-bundle figure that tree-shaking does not deliver; the attribution reading is cheap and tells the spec card what to promise. Seat to route; no ruling made here."
        }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    Claim amendment · domain:ui#4 · 2026-10-25T02:32Z · amends the claim 6392281867 (append-only; the claim's other lines stand)

    Premise fell (report 6392390016). @objectstack/spec/data exports no SystemFieldName (checked at runtime and in d.ts, at objectui's pin, the card's pin and objectstack main). Taking both imports off /system measured +382 B gz on the eager closure: zero saving. The repoint and the ceiling move are dropped, and no PR is owed for them.

    Narrowed to a reading (no PR, no commit): an attribution of the console production build. It names which eager modules keep /system (and /kernel, /api) in vendor-objectstack, with gz bytes per subpath share where the build can give them. The reading goes in a new os-dev-report on this card. The seat then carries the number to objectstack's domain:spec lane (the shared-chunk ESM build, stripReadDecorations / ValidateDataIssueSchema re-exports) and closes or re-queues this card to match.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 13447,
      "status": "reading",
      "branch": "claude/project-thread-wqfjll",
      "pr": null,
      "session": "session_01DRkSLfTy6PpiFqHxtNBjSa",
      "premise_still_valid": false,
      "summary": "Attribution reading under the amended claim (option C). On objectui main 6f629a7 the console's eager closure is 3,106,386 bytes gz across 85 of 2291 chunks; vendor-objectstack is 1,642,324 gz and holds 45 modules, nine of them @objectstack/spec subpath bundles. /system is the largest share (about 339 KB gz) and stays eager through exactly four objectui modules: flowResponse.ts and FlowRunner.tsx (chunk useConsoleActionRuntime: translateFlow, FLOW_SCREEN_FIELD_COPY_KEYS, resolveFlowScreenFieldOptions) plus the two SystemFieldName imports. That is why the earlier experiment that removed only the SystemFieldName pair read +382: the flow-runtime pair still holds it. /kernel (about 246 KB gz) is held by ten eager objectui modules, eight of them for stripReadDecorations alone, the others for ManifestSchema, deriveNamespaceFromPackageId, validateObjectNamespacePrefix and MetadataProtectionFields. /api (about 92 KB gz) cannot leave from the objectui side at all: @objectstack/client (WELL_KNOWN_CAPABILITY_KEYS, MetadataEventSchema, DataEventSchema, BulkDataEventSchema) and @objectstack/formula (StandardErrorCode) import it inside vendor-objectstack itself, besides four objectui modules. The card's whole-bundle figures overstate what lands but not by an order: rolldown keeps 53 percent of /system's 3,020,046 source bytes, 52 percent of /kernel's 2,231,176 and 20 percent of /api's 2,130,364 (rendered bytes after tree-shaking). Per-importer byte splits inside one subpath are NOT MEASURED: tree-shaken bytes are shared by every importer of the bundle, so a split needs one ablation build per importer.",
      "readings": {
        "build": "objectui main 6f629a7, spec pin per .objectstack-sha at that commit; console production build",
        "eager_closure": "3,106,386 B gz, 85 of 2291 chunks",
        "vendor_objectstack_gz": 1642324,
        "share_method": "rendered bytes per module from the build (after tree-shaking); gz share = rendered share x the chunk's 1,642,324 gz bytes (estimate); gz-alone = that module's rendered code gzipped by itself (an upper bound: the nine add up to more than the chunk)",
        "spec_shares_in_vendor_objectstack": [
          "/system   rendered 1,597,279 (20.7%) ~339,225 gz, gz-alone 424,409",
          "root      rendered 1,404,285 (18.2%) ~298,237 gz, gz-alone 380,016",
          "/kernel   rendered 1,160,462 (15.0%) ~246,455 gz, gz-alone 321,580",
          "/ui       rendered   847,848 (11.0%) ~180,063 gz, gz-alone 231,003",
          "/data     rendered   744,773 (9.6%)  ~158,172 gz, gz-alone 207,294",
          "/shared   rendered   669,435 (8.7%)  ~142,172 gz, gz-alone 184,712",
          "/api      rendered   433,184 (5.6%)   ~91,998 gz, gz-alone 123,344",
          "/automation rendered 238,531 (3.1%)   ~50,658 gz, gz-alone 64,698",
          "/security rendered    63,641 (0.8%)   ~13,516 gz, gz-alone 19,670",
          "spec total: 7,159,438 of 7,733,075 rendered bytes in the chunk (92.6%); the rest is @objectstack/formula, @objectstack/client, zod, cel-js, @objectstack/core logger"
        ],
        "system_eager_importers": [
          "packages/app-shell/src/utils/flowResponse.ts (chunk useConsoleActionRuntime): translateFlow",
          "packages/app-shell/src/views/FlowRunner.tsx (chunk useConsoleActionRuntime): FLOW_SCREEN_FIELD_COPY_KEYS, resolveFlowScreenFieldOptions, translateFlow",
          "packages/permissions/src/MePermissionsProvider.tsx (chunk ui-components): SystemFieldName",
          "packages/plugin-list/src/ListView.tsx (chunk plugins-views): SystemFieldName",
          "lazy only: metadata-form-i18n.ts, previews/doc-draft.ts (register-builtin-designers), @objectstack/lint, clientValidation.ts dynamic; packages/types nested-component-walk.ts is not in the output"
        ],
        "kernel_eager_importers": [
          "stripReadDecorations only: preview/capabilityLint.ts (index), preview/securityPostureLint.ts (ObjectView), metadata-admin/PermissionMatrixEditor.tsx (src), views/runtime-metadata-persistence.ts (runtime-metadata-persistence), data-objectstack draft-envelope.ts and index.ts (data-adapter)",
          "preview/DraftChangesPanel.tsx (ObjectView): MetadataProtectionFields, stripReadDecorations",
          "metadata-admin/package-schema.ts (packagedActions): ManifestSchema",
          "metadata-admin/PackageFormDialog.tsx (packagedActions): ManifestSchema, deriveNamespaceFromPackageId",
          "studio-design/packages-io.ts (packages-io): ManifestSchema, deriveNamespaceFromPackageId, validateObjectNamespacePrefix",
          "lazy only: metadata-admin/createBody.ts, studio-design/ObjectListViewInspector.tsx, @objectstack/lint; services/MetadataService.ts is not in the output"
        ],
        "api_eager_importers": [
          "@objectstack/client dist (vendor-objectstack): WELL_KNOWN_CAPABILITY_KEYS, MetadataEventSchema, DataEventSchema, BulkDataEventSchema",
          "@objectstack/formula dist (vendor-objectstack): StandardErrorCode",
          "packages/data-objectstack/src/index.ts (data-adapter): ValidateDataIssueSchema",
          "packages/data-objectstack/src/metadata-client.ts (data-adapter): FlowRegistrationSchema, GetMetaItemLayeredResponseSchema",
          "metadata-admin/DraftConflictDialog.tsx (packagedActions): GetMetaItemResponseSchema, MetadataConflictErrorSchema",
          "packages/core/src/utils/column-sortability.ts (framework): re-exports FIELD_UNSORTABLE_VIRTUAL_TYPE, FIELD_SORTABLE_UNPROVISIONED_ANCHOR"
        ],
        "also_noted": "the platform's own packages pull other subpaths into the same chunk: @objectstack/formula imports the spec root (3 sites), /data (7), /api (1), /security (2); @objectstack/client imports /data and /api. Root and /data stay eager through them whatever objectui does."
      },
      "tests": "Instrument: the console's own apps/console/vite.config.ts run through Vite's build() with one read-only module-dump plugin appended (generateBundle: per-module renderedLength, code gzipped alone, getModuleInfo importers / dynamicImporters), under scripts/pm/os-verify-lock.sh, after `CI=true pnpm exec turbo run build --filter=@object-ui/console^... --concurrency=2` (VERDICT command-exit 0). It wrote eager-closure.json 3,106,386 B gz / 85 of 2291 / vendor-objectstack 1,642,324. Calibration: the console's ordinary `CI=true pnpm exec vite build` in apps/console on the same tree (VERDICT command-exit 0) wrote the same three figures to the byte. Worktree clean at 6f629a7 throughout (git status empty). Bindings per importer read from the source import statements and the pinned client/formula dist.",
      "gates": "n/a: reading only, no diff, no PR",
      "dogfood_battery": "n/a: no PR",
      "mcp_calls": "0 this round (2 read-only issue_read calls in the previous round)",
      "api_writes": "1: this os-dev-report comment via the fleet-write relay (POST issues/13447/comments)",
      "open_questions": [
        {
          "question": "What should the objectstack domain:spec card promise?",
          "options": [
            "A: the shared-chunk multi-entry ESM build (the card's L item): it is the only lever that touches the duplication across all nine bundles, including root and /data that @objectstack/formula and @objectstack/client hold eager",
            "B: targeted re-exports so objectui can drop /system and /kernel: translateFlow, FLOW_SCREEN_FIELD_COPY_KEYS, resolveFlowScreenFieldOptions, SystemFieldName, stripReadDecorations, ManifestSchema, deriveNamespaceFromPackageId, validateObjectNamespacePrefix, MetadataProtectionFields from an already-eager subpath; ceiling of the gain about 585 KB gz (339 + 246) minus whatever those symbols drag in at their new home, NOT MEASURED",
            "C: B for /kernel only (one symbol, stripReadDecorations, covers 8 of its 10 eager importers), leaving /system to A"
          ],
          "recommendation": "A as the card, with the /system and /kernel importer lists above as its acceptance reading; B and C buy less than they look because each re-exported symbol may pull its schema graph into the new subpath's bundle, and /api cannot leave without client and formula changing too. Seat to route; no ruling made here."
        }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  8. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    Blocked · domain:ui#4 · 2026-10-25T03:16Z

    The objectui half as filed is void. @objectstack/spec/data exports no SystemFieldName, and taking both imports off /system measured zero (6392390016). The attribution reading (6392630038) shows what actually decides vendor-objectstack: the spec's self-contained subpath bundles, which @objectstack/formula / @objectstack/client also hold eager. objectstack#8133 is the carrier (spec shared-chunk build, claimed and in flight on objectstack's domain:spec lane); the reading is posted there.

    Blocked-by: objectstack-ai/objectstack#8133

    When it unblocks: once objectui's .objectstack-sha carries #8133, rebuild the console, read eager-closure.json, and lower MAX_EAGER_CLOSURE_GZIP_BYTES / BASELINE by the measured drop (objectui#11762's rule). The claim is released in this stroke: pm:dispatched → pm:blocked, assignee cleared.


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    Contributor

    Unlock scan: still blocked · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-25T16:59Z

    ⛔ Not a claim.

    Blocked-by: #13544


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:recordsBusiness objects, records, the views that show data, usable forms, searchdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpm:blockedpriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions