Repository navigation
console open: a nav entry and a page element bound to the same API dataSource read it twice — the page does not reuse the answer the nav gate already read #13323
Description
Filing-gate category: ① a reproduced defect (reach: below), and ③ directed by the maintainer on cloud#3103:
「在 objectui 立卡修重复读(导航门读到的结果给页面元素复用),挂 pm:queue。」
Reader: the domain:ui lane, through pm:queue. The change is in two files:
packages/react/src/element-data-source/useElementApiDataSource.ts(readElementApi);packages/app-shell/src/hooks/useNavMemberGates.ts.
It reaches cloud through a cloud pin move. Cloud's console-boots (pin-smoke, verify-console-pin.mjs, the cloud#2914 call budget) then measures it.
Dedupe: gh api search/issues, counting closed cards. Nothing open covers it.
repo:objectstack-ai/objectui readElementApi: 3, all closed (feat(layout,app-shell): a nav entry reads its declared API dataSource, so its visible sees the selected value as data #13095, navigation: read a nav entry's declared APIdataSource, so itsvisiblesees the selected value asdata(the objectui renderer half of objectstack-ai/objectstack#24427) #13029, feat(app-shell,react,types): generic product-page blocks (hero, stat, usage-bar, checklist, tile-grid) and the page element's API data source (objectui#12197) #12928).repo:objectstack-ai/objectui useNavMemberGates: 25, all closed among the shown; nearest navigation: read a nav entry's declared APIdataSource, so itsvisiblesees the selected value asdata(the objectui renderer half of objectstack-ai/objectstack#24427) #13029, feat(layout,app-shell): a nav entry reads its declared API dataSource, so its visible sees the selected value as data #13095, fix(app-shell): the app landing waits on its nav entries' pending API reads #13105.repo:objectstack-ai/objectui "second fetch": 108; the nearest is Record page: opening a record sends one approvals query and one record fetch, not three and two #12701, the record page's request count, a different surface.
#13029 is the closest: it added the nav entry's read. Its scope said "The reader reuses useElementApiDataSource, with no second fetch". Its contract review set the request count at "once per distinct binding per hook instance, sharing in flight" (comment). The duplicate below is outside that bound. This card asks for the next property: one read per open, across the nav gate and the page.
What happens
A nav entry declares an API dataSource, and the page it opens binds the same read on an element. Two things then happen:
- The nav gate reads the URL first (
useNavMemberGates→readElementApi). - About 300 ms later, the page element reads it again (
useElementApiDataSource→readElementApi).
readElementApi shares a request only while it is in flight: .finally(() => IN_FLIGHT.delete(url)). When the nav read has settled before the page element mounts, a second GET goes out for an answer the console already holds.
reach: measured on cloud's control-plane console
Setup:
- objectui
56cf4d8e(production console build). - The cloud rig:
run-stack.sh --seed --with-ui --prod-console. - An ordinary organization owner, warm opens,
zh-CN, 1299×1119.
The bindings in cloud:
- The sidebar entry
nav_environmentsdeclaresdataSource: { provider: 'api', read: { url: '/api/v1/cloud/home' }, path: 'data' }(cloud#3002, cloudpackages/app-cloud/src/cloud.app.ts). - The
welcomeandpricingpages bind the same read on their root element (HOME_SUMMARY_BINDING).
Readings, 8 opens per page, counted from the page's performance entries and from a window.fetch tracer:
page/welcome |
page/pricing |
|
|---|---|---|
| as served | GET /api/v1/cloud/home ×2 on 8 of 8 opens |
×2 on 8 of 8 |
only nav_environments.dataSource stripped from /api/v1/meta/app in the browser |
×1 on 8 of 8 | ×1 on 8 of 8 |
The tracer's two stacks:
- the first
GETfrom the nav gate's effect,readElementApiviauseNavMemberGates; - the second from
useElementApiDataSource's effect.
Cloud CI (console-boots) failed twice on it: run 39755148162, run 39759792471. The failures:
page/welcome (home): 1 URL(s) asked more than once: …/api/v1/cloud/home x2page/pricing (billing): 23 API calls, budget 22
The maintainer waived console-boots once, for cloud#3150 only. Every later cloud pin PR's console-boots stays red on this until it lands.
Expected
On one console open, a nav entry's API dataSource and a page element bound to the same read make one request. The page element takes the answer the nav gate already read.
Renderer only: no spec or contract change. Both bindings are already the spec's ElementApiDataSource.
These hold as today:
- Fail-closed nav gate: a nav entry stays hidden while its read is pending or failed (navigation: read a nav entry's declared API
dataSource, so itsvisiblesees the selected value asdata(the objectui renderer half of objectstack-ai/objectstack#24427) #13029). - No stale answer across opens: a new open, or an element's own refresh after an action, reads again. "It caches no answer" stays true beyond the one open. Only the second read within an open is the defect.
Acceptance notes
- A test in
packages/app-shellorpackages/react: an app whose nav entry and whose page's element bind the same{ provider: 'api', read: { url } }mounts and settles. It records exactly one call of the hostapiFetchfor that URL, including when the nav read settles before the page element mounts (the caseIN_FLIGHTmisses). - Ablation: without the reuse, 2 calls.
- A second test: a later open (a new route visit), or the element's refresh, makes a new call.
- The consumer reading: cloud's
console-bootson the pin PR that carries the fix showspage/welcomewith no duplicate URL, andpage/pricingwithin its budget of 22. The budget is not moved.
Suggested priority: p2. The cost is one extra control-plane request per open of these pages, and a red console-boots on each cloud pin PR until this lands.
Activity
objectstack-fleet commentedon Oct 22, 2026
Claim: PM loop round 1 · 2026-10-22T15:51Z
Session:
session_01Nb7Hm9kSvmuJQ8Gs9n7QPL(the card session that implements; dispatched by this project's coordinator. The seat that writes this claim isdomain:uiseat 1,session_01WJozybDmRH8z2c5SD7vJkj)Account:
os-sales(the seat's linked user; the card's assignee)Branch:
claude/issue-13323-reuse-nav-readWorktree:
objectui-issue-13323Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/react/src/element-data-source/**(readElementApi's one-open reuse and its tests),packages/app-shell/src/hooks/useNavMemberGates.tsand its tests, possibly the console's open-boundary wiring inapps/console/src/**, the two packages' READMEs, the matchingcontent/docs/guide/**page,.changeset/(stop on breach; explain in the report)Container & model:
M,mode:thread(a card session of the Sales account's project, baseorigin/main74ebad0),model: opus (default; dispatch-gates --tier --repo objectstack-ai/objectui answered "no path-derived mandate"),effort: highClause-②: yes
Responsibility:
objectui's readElementApi, whose in-flight sharing (.finally deletes the IN_FLIGHT entry) lets a settled nav-gate read be fetched again by the page element | no platform path covers it: #13029's contract bound the count per hook instance, not per open | cloud's console-boots pin smoke reaches it on every cloud pin PR (two red runs on the card); every console app whose nav entry and page bind the same API read pays one extra request per openThread-read: none
Serial constraints cleared: none (no open
pm:dispatchedcard or open PR of this lane namespackages/react/src/element-data-source/**oruseNavMemberGates.ts; objectui#13324's PR #13326 touchespackages/permissionsandapps/console/src/AppContent.tsxonly, and objectui#13183 is on list bulk actions)Why
Clause-②: yesalthough no spec moves: marking "one open" may need a new export from@object-ui/reactfor@object-ui/app-shellto consume, which widens the public surface. The declaration has to survive a route the implementer has not chosen yet, so it isyeswhen unsure. If the delivered diff adds no export reachable from either package's entry, the report says so with the reading, and the seat's review records it.objectstack-fleet commentedon Oct 22, 2026
File surface revised ·
domain:uiseat 1 ·session_01WJozybDmRH8z2c5SD7vJkj· 2026-10-22T15:55Z · amends claim6345071397, same session and branch.The implementer reported the breach before writing it: the one-open boundary is wired in
packages/app-shell/src/console/ConsoleShell.tsx(ConnectedShellInner, whereapiFetchis injected and the language remount lives), not inapps/console/src/**, plus one new internal file inpackages/app-shellfor the boundary component. Accepted; the revised file surface is:packages/react/src/element-data-source/**,packages/react/src/index.ts(the newElementApiOpenScopeexport, which keepsClause-②: yes),packages/app-shell/src/hooks/useNavMemberGates.ts,packages/app-shell/src/console/ConsoleShell.tsxand one new internal file beside it, their tests, the two packages' READMEs, the matchingcontent/docs/guide/**page,.changeset/.Same lane (
domain:ui), same packages family; no other open claim of this lane names these files.fix(app-shell): name each console open uniquely, so Back to an entry …
docs(react): make the ElementApiOpenScope README snippet compile on i…
fix(react,app-shell): a nav entry and a page element bound to the sam…
objectstack-fleet commentedon Oct 22, 2026
LANDED ·
domain:uiseat 1 ·session_01WJozybDmRH8z2c5SD7vJkj· 2026-10-22T18:06Zb911ebb4e6ed19ac43e87d00304861718a636679(heada295d34)origin/maincontentpackages/react/src/element-data-source/useElementApiDataSource.tsatmaindeclaresexport function ElementApiOpenScope1 time(s) (0 at1aa88519)State: the card closed on the merge;
pm:dispatchedcomes off in this stroke. The card's consumer reading (cloudconsole-boots:page/welcomewith no duplicate URL,page/pricingwithin 22) belongs to the next cloud pin PR that carriesb911ebb; this lane cannot read objectstack-ai/cloud.