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 #25925

Closed

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 915e940)

  • 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
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    enhancementNew feature or request
    and removed on Oct 24, 2026
  2. 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

  3. 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 objectstack-ai/objectui#13474 does not touch the file at this reading) and in seat 4's PR objectstack-ai/objectui#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.
  4. 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

  5. 7 remaining items

  6. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Unlock scan: blocker moot, waiting on the transfer · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-26T02:53Z

    ⛔ Not a claim.

    Blocked-by: #25854


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Transferred 2026-10-26T04:15Z from objectstack-ai/objectui#13447, with its comments and timeline; the old URL redirects here. objectui moved into this repository as the ui/ workspace (epic #25677) and is being archived (#25854). The body is left exactly as filed.

    Paths. Read every repository path in the body with a ui/ prefix: packages/permissions/src/MePermissionsProvider.tsx is now ui/packages/permissions/src/MePermissionsProvider.tsx; packages/plugin-list/src/ListView.tsx is now ui/packages/plugin-list/src/ListView.tsx; packages/app-shell/src/services/MetadataService.ts is now ui/packages/app-shell/src/services/MetadataService.ts; packages/data-objectstack/src/index.ts is now ui/packages/data-objectstack/src/index.ts; scripts/check-eager-closure-budget.mjs is now ui/scripts/check-eager-closure-budget.mjs.

    Not found under ui/ or at the root on main e167956e3f: apps/console/dist/eager-closure.json; re-check that premise before work starts.

    No stale pm:dispatched or assignee to strip.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Unlock scan: unlocked → pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-26T07:57Z

    ⛔ Not a claim, ⛔ not a dispatch.


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1
    Session: session_017iXjUm1rujwDk7f3KT1Pkk (seat); implementing card thread session_01PykFDU1CQLdgAD1T6LPhLS
    Account: os-steve
    Branch: claude/project-thread-oaf230 (platform-assigned card-thread branch; a card thread can push only its assigned branch, and the name carries no issue number, so this claim is the identity record)
    Worktree: the card thread's own container
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: ui/packages/permissions/src/MePermissionsProvider.tsx and ui/packages/plugin-list/src/ListView.tsx (one import line each: SystemFieldName from @objectstack/spec/data instead of /system), the file that holds MAX_EAGER_CLOSURE_GZIP_BYTES (lowered by the measured amount, objectui#11762 rule), scripts/sdui-manifest.record.json (derived hash), changeset. The PR states the eager-closure.json reading before and after. The spec half (re-exporting stripReadDecorations / ValidateDataIssueSchema from a loaded subpath) is domain:spec work, filed once this reading gives the number; not in this card. plugin-list is seat 2's package (one import line; seat 2 told) (stop on breach; explain in the report). ⛔ ui/.github/** and the root .github/workflows/ci.yml are out of bounds (maintainer's word, ui-merge epic in flight). Changeset in the root .changeset/.
    Container & model: S, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: no (import paths and a budget constant; no exported type change)
    Metadata-protocol: none
    Responsibility: n/a: renderer defect in ui/, the producing code is the cited ui file; no platform path covers it; reached through the public Console
    Thread-read: 6411044444
    Premise: holds (read-only check by the seat at origin/main: both SystemFieldName imports still read @objectstack/spec/system 2026-10-26T12:23Z)
    Serial constraints cleared: manifest-hash single token: this PR re-records the sdui hash, so it enters the merge queue only when the seat hands it the token (order on the seat post); no open PR edits these two import lines (open-PR file scan 2026-10-26T12:23Z)

    Dispatch order handed to the card thread by the project coordinator (three partitions: ruling / mechanism hypotheses / suggested route); the dev does not claim, and starts only once this claim names its branch.

  10. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 25925,
      "status": "done",
      "branch": "claude/project-thread-oaf230",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26127",
      "session": "session_01PykFDU1CQLdgAD1T6LPhLS",
      "premise_still_valid": false,
      "summary": "Measured first, per the seat's acceptance. The repoint half is void: packages/spec/src/data/index.ts exports no SystemFieldName on main cc378e93 (declared in system/constants/system-names.ts, reached through system/index.ts only), and an uncommitted experiment replacing both imports with a local literal moved the eager closure by -161 B gz, because FlowRunner.tsx and flowResponse.ts still import /system by value. The ceiling half holds: on main the gate exits 2, its sensitivity half calling the aggregate ceiling (2.25x) and the vendor-objectstack row (1.91x) blind after the spec shared-chunk build and the move into ui/. PR #26127 lowers both by exactly what their payload lost (3,579,945 to 2,489,948; 1,867,000 to 842,730), keeping each line's previous headroom, re-pins BASELINE and PER_CHUNK_BASELINE vendor-objectstack onto cc378e93, and moves the two rendered-reading literals in the unit test. Touches only ui/scripts/check-eager-closure-budget.mjs and its test: no ui/packages change, no sdui record change, no merge-queue token needed. PR body says Part of #25925, not Fixes: the seat decides whether the card closes or goes back to triage.",
      "tests": "Readings, one container: `pnpm --filter '@object-ui/console^...' build` (os-verify-lock VERDICT command-exit 0, 720s), then `CI=true pnpm exec vite build` in ui/apps/console (VERDICT command-exit 0), reading ui/apps/console/dist/eager-closure.json. Control main cc378e93: 1,982,059 B gz, 85 of 2387 chunks, vendor-objectstack 507,716. Experiment (both SystemFieldName imports -> local literal; marker grep 1 and old import grep 0 in both files before the build; trap restore with git checkout HEAD --, blob hashes equal HEAD and git diff HEAD empty after): 1,981,898, 85 of 2387, vendor-objectstack 507,693, delta -161. Re-read after the edit (same tree content for the bundler): 1,982,059 to the byte. Gate after the re-pin: closure pass 1935.6 / 2431.6 KB, per-chunk pass x4, sensitivity pass x5 (0.71x, 0.47x), exit 1 on the membership half only (pre-existing on main). Unit tests at 6a75282d: `./node_modules/.bin/vitest run --maxWorkers=2` in ui/ over check-eager-closure-budget, check-eager-locale-catalogues, check-side-effects-array, vite-declared-lazy-views, vite-types-zod-lazy, vite-ineffective-dynamic-imports: Test Files 6 passed (6), Tests 300 passed (300); before the literal move the same run failed exactly the 2 rendered-reading cases. No ablation: the diff changes budget constants and pins, no tested behaviour.",
      "gates": "Local derived set at 6a75282d (`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, 18 families), each exit captured before any pipe: check-closing-keyword-parity (+ --self-test), check-comment-mask-corpus, check-undeclared-dep-imports (+ --self-test), check:cross-package-test-inputs, check:driver-memory-census, check:engine-double-contract, check:gitlink-declared, check:nul-bytes, check:published-files, check:query-options-erasure, check:refd-timer-probe, check:tier-file-adoption, check:type-check-coverage, check:type-check-debt, check:watch-hint-literal, check:where-matcher: all exit 0. `--ran` with exit codes: 18 derived, 18 run, 0 NOT-MEASURED (a derived zero). CI families: in_progress at report time, read from the PR's check-runs by the seat.",
      "dogfood_battery": "n/a: no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "5: mcp__github__issue_read get, get_comments x2 on #25925, get_labels on 26127 (failed, not an issue), mcp__github__pull_request_read get on #26127; all read-only, no write tool",
      "api_writes": "2: pr_create #26127 via the fleet-write relay (with-fleet.sh --via dispatch, labels skip-changeset, assignees os-steve; read-back identical, 5094 bytes) and this os-dev-report comment via post-stamped (POST issues/25925/comments); plus git push of the branch (not a REST write)",
      "open_questions": [
        {
          "question": "What happens to the card once #26127 lands?",
          "options": [
            "A: close #25925 on #26127: the repoint item is void with evidence and the ceiling item is done; the spec half is filed separately as triage already said",
            "B: send it back to triage for the spec half (stripReadDecorations / ValidateDataIssueSchema re-exports) under this number"
          ],
          "recommendation": "A, because triage already split the spec half off this card and both ui items are now settled by measurement. Seat to route."
        }
      ],
      "out_of_scope_findings": [
        "class: a · reach: `node scripts/check-eager-closure-budget.mjs` in ui/ after a console build of main cc378e93 prints a red membership verdict (`packages/core` declared in `framework`, 1 of 90 modules in `vendor-objectstack`) and exits non-zero before and after this PR · evidence: gate output in the PR body; which module moved NOT MEASURED; fix site is the grouping rules in ui/apps/console/vite.config.ts · dedupe words: eager-closure membership packages/core framework vendor-objectstack",
        "carrier: none · noted, not filed: no workflow under .github/workflows runs check:eager-closure today (grep of .github/workflows and ui/.github finds no caller), so the console budget gate is local-only until the ui CI port lands; recorded in the PR's Acceptance notes"
      ]
    }

    Generated by Claude Code

  11. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Claim amendment (seat domain:ui#1, 2026-10-26T13:11Z): amends the claim 6415922107 after the measurement it asked for (report 6416818207). Append-only; the lines not named here stand.

    Readings (same container, same instrument): main at cc378e93 1,982,059 B gzip; with the two SystemFieldName imports swapped 1,981,898 B. A difference of 161 B is zero saving.

    File surface, replaced: the two import-line edits (MePermissionsProvider.tsx, ListView.tsx), scripts/sdui-manifest.record.json and the changeset are dropped. The surface is now ui/scripts/check-eager-closure-budget.mjs and its unit test ui/scripts/__tests__/check-eager-closure-budget.test.ts.

    What changes: the aggregate ceiling and vendor-objectstack's per-chunk row come down by exactly the bytes the closure lost since the previous baseline, keeping their old headroom. BASELINE is re-pinned to cc378e93. On main the gate's sensitivity half exits 2: it calls the aggregate (2.25x) and vendor-objectstack (1.91x) blind.

    Serial constraints: no ui/packages/** source changes, so the sdui manifest hash does not move and no token is needed. Lands as an ordinary queue PR (#26127). The spec half named in the claim is moot, since @objectstack/spec already ships one shared-chunk graph.

    Card disposition: Part of #25925 in the PR. The seat closes the card when #26127 lands, because the premise's duplication has gone and the gate it left blind is re-pinned.

  12. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Seat close-out · domain:ui seat 1 · 2026-10-26T13:46Z: PR #26127 merged at 2026-10-26T13:46Z (merge commit ada3cbb02a33), carrying Part of #25925. The seat closes the card as the claim amendment 6416858265 said it would.

    No remaining item is owed, so the card closes as completed and pm:dispatched comes off. If triage reads a remaining item differently, reopen it with that item named.

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

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchdomain:uienhancementNew feature or requestpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions