Skip to content

console: on an app page, answer /meta/view, /meta/page and /meta/dashboard from the app bundle (#28321) instead of three list reads; page/pricing 24 to ~21 calls #28645

Closed
1 of 1 issue completed

Description

@objectstack-fleet

repo:cloud#2 · os-zhuang · session_0123kRqqdpAJWYMgsgdAJX4G

Filing gate ①: a console performance gap, measured. The maintainer accepted the +1 call for now (cloud budget 23 → 24, 2026-11-01). This card is the way back down.

What happens

Since #28321 ("entering an app loads its metadata bundle once"), a warm open of an app page fetches GET /api/v1/meta/app/<app>/bundle once. The same open still makes the per-type list reads GET /api/v1/meta/view, GET /api/v1/meta/page and GET /api/v1/meta/dashboard, even though the bundle already holds that app's views, pages and dashboards. On cloud's control-plane console, page/pricing went from 23 to 24 calls and page/welcome from 24 to 25. Each differs by exactly the bundle call, and no URL is asked twice. Read by cloud's pin smoke at framework bca27ad3, production console build, zh-CN.

Ask

On an app page, once the app's bundle is loaded, answer the view, page and dashboard metadata the page needs from the bundle instead of the three list reads. Fall back to the list read only for an item the bundle does not hold. That brings the measured open to about 21 calls. Keep the bundle's If-None-Match / 304 revalidation.

Business reason

The console's open path is the product's first impression. A measured waterfall is tracked downstream (cloud's console-open card). Every call removed here shortens the chain on every hosted environment, not only cloud's.

Reader

The console metadata owner, through objectstack triage. Cloud lowers its call budget when a pin carries this.

Dedup

#28321 introduced the bundle, and #27627 is its parent. No card covers folding the list reads into the bundle.

Activity

  1. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p3 · domain:ui · area:records · pm:queue · 2026-11-01T10:53Z

    ⛔ Not a claim.

    • Read fresh, and measured by cloud's pin smoke. An app page still makes three list reads (/meta/view, /meta/page, /meta/dashboard) that the feat(console): entering an app loads its metadata bundle once, and a record open reads no metadata #28321 bundle already answers. The maintainer accepted +1 call for now, so the filer's p3 stands.
    • The fix is in the Console's metadata reads only. No cloud change is needed, so it stays in the framework domain:ui lane. The claim keeps the bundle's If-None-Match / 304, and falls back to the list read only for an item the bundle does not hold.

    Generated by Claude Code

  2. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Claim: PM loop round 1 · 2026-11-01T13:12Z
    Session: session_01QsR2jUjXYpqdaAkEWBHbqG (card thread, os-dev); dispatched by seat session session_01QsR2jUJ19MstFvFhjgiYTu
    Account: zhuangjianguo
    Branch: claude/project-thread-6p9fk2 (platform-assigned to the card thread; it can push only this branch)
    Worktree: objectstack-issue-28645
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: ui/packages/app-shell/src/providers/MetadataProvider.tsx (the per-type view / page / dashboard list reads on an app page), ui/packages/data-objectstack/src/index.ts (AppBundleStore and the bundled reads), their tests, and a root .changeset (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: 6556980345
    Premise: holds (at origin/main e4ec4f22, MetadataProvider's ensureType still lists each type with client.meta.getItems(type); the bundle answers only by-name getItem reads)
    Serial constraints cleared: none (no live claim or open card PR of seat 4 names either file)

    Keep the bundle's If-None-Match / 304 revalidation, and fall back to the list read only for an item the bundle does not hold. Measure the call count of a warm app-page open before and after on a production Console build (the card reads ~24 → ~21). If the fix needs a published type or export of @object-ui/data-objectstack to change, the report says so before pr_create and the seat amends the Clause-②: line.

  3. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Claim amended · 2026-11-01T13:16Z · size and file surface; it supersedes the Container & model: and File surface: lines of this seat's claim 6558417171. Branch, session and declaration lines are unchanged (Clause-②: no, Metadata-protocol: none).

    The card thread measured (needs_decision, project file issue-28645/needs-decision.md, origin/main 2678600d) that the declared surface cannot remove the three list reads: every reader reads a whole list and looks a name up in it, and NavigationSyncEffect holds the page and dashboard reads on every app page. The card goes in two PRs:

    Container & model: L, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
    File surface (PR 1): ui/packages/app-shell/src/providers/MetadataProvider.tsx, ui/packages/data-objectstack/src/index.ts, ui/packages/app-shell/src/views/PageView.tsx, ui/packages/app-shell/src/console/AppContent.tsx (page object scope only), ui/packages/app-shell/src/layout/AppHeader.tsx (phone title), RecordDetailView.tsx (page lookup only), useRecentItemLabel, useNavTargetLabel, hooks/useServedViewItems.ts, their tests, and a root .changeset (stop on breach; explain in the report). ⛔ useNavigationSync.ts is not in PR 1.
    Serial constraints cleared: seat 4's #28470 names RecordDetailView.tsx (record page readers); PR 1 touches only its page-by-name lookup there, and whichever lands later merges main.

  4. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Claim amended · 2026-11-01T13:27Z · declaration line and file surface; it supersedes the Clause-②: line of claim 6558417171 and adds to the PR 1 file surface of amendment 6558473050. Branch, session, size and Metadata-protocol: none are unchanged.

    Clause-②: yes (widening)
    Metadata-protocol: none

    The card thread measured that PR 1 widens the published surface of @object-ui/data-objectstack: ObjectStackAdapter gains a public peekAppBundle(): AppBundlePeek (reads the active bundle without waiting), and index.ts newly exports the types AppBundlePeek, AppBundleItems and AppBundleEntry from ./app-bundle. Nothing is removed or narrowed. The changeset stays patch; the Clause-②: yes declaration owes this seat's TIER_DEFAULT review before ACCEPT.

    File surface (added): ui/packages/data-objectstack/src/app-bundle.ts (AppBundleStore.peek()). RecordDetailView.tsx drops out of PR 1 (unchanged; react's usePageAssignment reads the page list on every record route anyway), so PR 1 no longer shares a file with seat 4's #28470.

  5. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Claim amended · 2026-11-01T15:13Z · PR 1 file surface widened; it adds to amendments 6558473050 and 6558598734. Branch, session, size and declaration lines are unchanged.

    The card thread measured PR 1 at head c6f9db6c against 2678600d on a production Console build (showcase app, warm reload): net-neutral (page 26 → 26, dashboard 35 → 35). /meta/view is still read because the root prefetch composes the package scope before the bundle is entered, the scope holds objects the bundle lacks, and useObjectPresence forces the view list. The seat does not ship a net-neutral PR that widens a published surface, so PR 1 takes the view saving itself.

    File surface (added): ui/packages/app-shell/src/console/appObjectScope.ts, ui/packages/app-shell/src/console/ConsoleShell.tsx (enter the bundle once at the root; AppContent reuses it), ui/packages/app-shell/src/hooks/useObjectPresence.ts (ask its object by name), their tests. A reader may skip the view list only when its output is identical with and without it on the showcase app; the report lists any that keep it. If the root enter makes peekAppBundle and its three exported types unnecessary, the dev drops them and this seat sets Clause-②: back to no.

  6. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUjXYpqdaAkEWBHbqG
    os-dev-report

    {
      "issue": 28645,
      "status": "done",
      "branch": "claude/project-thread-6p9fk2",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28754",
      "session": "session_01QsR2jUjXYpqdaAkEWBHbqG",
      "premise_still_valid": true,
      "summary": "PR 1 of #28645 (Part of, not Fixes). The app page's views, its page and nav dashboard reads are bundle-first. The console enters the app bundle once at its root and AppContent reuses the entry. Scope views come from the bundle for bundled objects, and the /meta/view list is read only when an asked name is outside the bundle. Presence asks with views:false. New peekAppBundle + three exported types (Clause-② yes (widening)). Warm reload on a production build (showcase_app, base 2678600d): page 26->26 (view -1, /packages +1 timing), dashboard 35->35, object list 33->33. Expected with PR 2: page 24, dashboard 33.",
      "tests": "427 test files naming the touched modules, 6 locked batches --maxWorkers=2: 427/427 files, 3527 tests passed. New pins: MetadataProvider.bundleFirstReads-28645 (17), appBundlePeek-28645 (5), appObjectScope-12811 +1. Ablations each red then restored: EAGER view back (5 red), readBundledViews MISS (1), views:false off (1), pending-before-enter off (1), bundled-keeps-bundle-views off (1), root enter off (1). turbo type-check app-shell + data-objectstack 66/66 exit 0. eslint --quiet on changed ui files: 0 errors.",
      "gates": "35 derived (dispatch-gates --commands at 23fefe55), all exit 0; --ran: 35 derived, 35 run, 0 NOT-MEASURED. check-sdui-manifest re-run at final head 75df9274: exit 0. PR-body gates with GITHUB_EVENT_PATH: check-changeset-no-major exit 0, check-adr-0087-registration exit 0, check-closing-keyword-parity exit 0, check-partof-closing-keyword exit 0. CI check-runs: not yet reported (PR just opened).",
      "line_budget": "21 files, +1220/-59 at 23fefe55 (under the 3000-line human-merge threshold)",
      "deviations": [
        "/api/v1/packages +1 on the page route: PageView draws on the bundle ~250 ms earlier, so its Studio design gate misses the sidebar gates' in-flight window; packages-io forbids a reuse window (seat ruling)",
        "dashboard route keeps /meta/view: whole-registry objects read, as on main (seat ruling)",
        "object list route keeps /meta/view: lookup target sys_user is outside the bundle",
        "file surface past the first claim: app-bundle.ts, new bundledReads.ts, appObjectScope.ts, useObjectPresence.ts (amendment 6559809254); AppContent page route drops the page bucket wait; AppHeader useServedViewItems(read) gate; RecordDetailView unchanged",
        "enterAppBundle keys the root entry by app name because AppContent reads the console's approval-reads wrapper of the adapter",
        "a miss falls back to the list read rather than a by-name read, keeping prefer-local",
        "pins updated for the dropped eager view read: objectScope-12811, namesOnlyScope-12980, oneMetadataRead-13044, switchDropsAdapter-13044, ConnectedShell.sessionGate, appObjectScope-12811"
      ],
      "files_changed": [
        ".changeset/28645-app-page-reads-from-bundle.md",
        "ui/packages/app-shell/src/console/AppContent.tsx",
        "ui/packages/app-shell/src/console/__tests__/ConnectedShell.sessionGate.test.tsx",
        "ui/packages/app-shell/src/console/__tests__/appObjectScope-12811.test.tsx",
        "ui/packages/app-shell/src/console/appObjectScope.ts",
        "ui/packages/app-shell/src/hooks/useNavTargetLabel.ts",
        "ui/packages/app-shell/src/hooks/useObjectPresence.ts",
        "ui/packages/app-shell/src/hooks/useRecentItemLabel.ts",
        "ui/packages/app-shell/src/hooks/useServedViewItems.ts",
        "ui/packages/app-shell/src/layout/AppHeader.tsx",
        "ui/packages/app-shell/src/providers/MetadataProvider.tsx",
        "ui/packages/app-shell/src/providers/__tests__/MetadataProvider.bundleFirstReads-28645.test.tsx",
        "ui/packages/app-shell/src/providers/__tests__/MetadataProvider.namesOnlyScope-12980.test.tsx",
        "ui/packages/app-shell/src/providers/__tests__/MetadataProvider.objectScope-12811.test.tsx",
        "ui/packages/app-shell/src/providers/__tests__/MetadataProvider.oneMetadataRead-13044.test.tsx",
        "ui/packages/app-shell/src/providers/__tests__/MetadataProvider.switchDropsAdapter-13044.test.tsx",
        "ui/packages/app-shell/src/providers/bundledReads.ts",
        "ui/packages/app-shell/src/views/PageView.tsx",
        "ui/packages/data-objectstack/src/app-bundle.ts",
        "ui/packages/data-objectstack/src/appBundlePeek-28645.test.ts",
        "ui/packages/data-objectstack/src/index.ts"
      ],
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft) and this os-dev-report comment (post-stamped); plus git push",
      "open_questions": [],
      "out_of_scope_findings": [
        "MetadataProvider: a 'none' bundle ask recorded during a render that does not re-render the provider waits until the provider's next commit to settle as a miss (edge seen only in reasoning, not reproduced) · noted, not filed"
      ]
    }

    Generated by Claude Code

  7. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Landed (PR 1 of 2) · 2026-11-01T18:13Z · PR #28754 merged through the merge queue as 706ac52d at 2026-11-01T18:12:59Z (GitHub's clock). Contract review TIER_DEFAULT PASS 6561446838 and ACCEPT 6561656747, both at head 935a89e3.

    probe before (706ac52d~1) now (origin/main)
    peekAppBundle in ui/packages/data-objectstack/src/index.ts 0 2
    ui/packages/app-shell/src/providers/bundledReads.ts exists no yes

    Part of #28645: the card stays open and pm:dispatched. PR 2 (#28680, ruled A: write navigation at page/dashboard create, delete and rename instead of NavigationSyncEffect's list diff) opens next on the same thread and branch, expected at page 24 / dashboard 33 requests.


    Generated by Claude Code

  8. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

    Landed · 2026-11-01T20:46Z · PR #28783 (PR 2 of 2) merged through the merge queue as c064d3a2 at 2026-11-01T20:45:24Z (GitHub's clock). ACCEPT 6563459505 at head afd4ebd6. PR 1 was #28754 (706ac52d).

    probe before (c064d3a2~1) now (origin/main)
    NavigationSyncEffect in console/AppContent.tsx 2 0
    useNavigationWrites in metadata-admin/ResourceEditPage.tsx 0 2

    Measured by the dev on a production build (showcase_app, warm reload): page 26 → 24, object list 33 → 31, dashboard 35 → 34. The dashboard route's last /meta/dashboard read is #28784. Fixes #28645 and Fixes #28680 closed both cards; pm:dispatched comes off in the same stroke as this note.


    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

Labels

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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions