Skip to content

feat(console-ai): bind-on-create — build conversations re-key to app:X:build (ADR-0057 A1.b) - #2466

Merged
os-zhuang merged 4 commits into
mainfrom
claude/determined-herschel-fc7c63
Jul 13, 2026
Merged

feat(console-ai): bind-on-create — build conversations re-key to app:X:build (ADR-0057 A1.b)#2466
os-zhuang merged 4 commits into
mainfrom
claude/determined-herschel-fc7c63

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Implements ADR-0057 Amendment A1.b (#2457) — part of epic #2409. Follows A1.a (#2461).

The defect (reproduced live)

A bare /ai/build visit (the magic flow) keys its conversation to the product-only scope build, while "Edit with AI" (/ai/build?package=X) keys app:X:build. When a build inside an unbound conversation mints package X, the thread that built X and the thread Edit-with-AI later opens for X are different conversations — the user's original build history is stranded where they'll never look for it (Amendment A1, defect 3).

What this does

  • Bind on create (the untitled-document idiom): the moment a product-scoped build thread's history binds to package X (latest draftReview/builderHandoff package, per A1.a's deriveBoundPackageId), the page calls the new useChatConversation.rekeyScope('app:X:build') and puts ?package=X on the URL. A later Edit-with-AI entry for X resumes the same thread.
  • rekeyScope is synchronous by design: it flips conversationScope (ref) before the ?package= navigate re-render recomputes the host scope, so the AI handoff: second handoff's auto-send doesn't fire into an existing (hydrating) build conversation #2450 scope-match gate never opens a remount window — the mounted pane (and any in-flight stream) survives the re-key. Binding is deferred until the conversation id is mirrored into the URL (single-navigator rule: the URL-mirror effect is dormant once /:convId is present, so the two effects can never fight over the URL from stale closures).
  • Legacy-scope fallback read (migration): an /ai/build?package=X visit with no app:X:build cache entry offers the product-only thread to a predicate — adopted iff its own history is bound to X, so an unrelated thread is never hijacked into an app scope. A failing fallback fetch degrades to a plain miss (fresh conversation), never a dead surface. Pre-A1.b threads therefore stay reachable.
  • A1.a chip → switcher: the binding chip is now a dropdown — apps (deduped by package) navigate to that app's Edit-with-AI thread; "✨ New app" opens a fresh unbound draft via ?new=1. Trigger keeps data-testid="ai-build-package-chip".

Migration / keying semantics — read this

This mutates live conversation keying, client-side only:

  • Scope keying is a per-(user, scope)localStorage cache (objectstack:ai-chat-conversation-id:{user}:{scope}); useChatConversation never lists by scope server-side, so no server change is needed. Corollary (pre-existing): continuity is per-browser; a different browser has no cache and the fallback/predicate handles or re-mints there.
  • The legacy product-only key is deliberately NOT cleared on re-key or adoption — ChatDock/FAB and bare /ai/build keep resolving through it exactly as before. Zero regression for those surfaces; the bound thread is simply also reachable under its app scope.
  • Latest-wins: re-keying overwrites an existing app:X:build entry — the thread you most recently had open bound to X becomes X's Edit-with-AI thread (matches the chip's latest-draft-wins semantics). Older threads remain in the sidebar history.
  • Known gap deferred to A1.c: useObjectChat bakes body.context into the transport at first render, so turns between the bind and the next reload don't carry context.packageId — same as today; the server tracks the conversation's active package itself (ADR-0070).

Tests

8 new cases in useChatConversation.test.tsx (re-key writes both keys + same id; rekeyed scope change resumes without re-resolve or create; no-op before resolve; legacy adopt on match / fresh on reject / fresh on fetch failure; predicate fed the localStorage message cache when the server returns no history; fallback never runs on a primary cache hit). Existing #2450/A1.a suites green: useDeferredFirstSend, deriveBoundPackageId, AiChatPage.hydration, chatScope, useObjectChat.handoffContext — 56 tests total, plus tsc --noEmit clean.

Live browser proof of the continuity fix + legacy fallback to follow in a PR comment before merge.

🤖 Generated with Claude Code

… to app:X:build when it mints X (ADR-0057 A1.b)
The magic flow (bare /ai/build) keys its conversation product-only, while
Edit-with-AI keys app:X:build — so the thread that BUILT app X and the
thread Edit-with-AI later opens for X were different conversations and the
build history was stranded (Amendment A1 defect 3, reproduced live).
- useChatConversation.rekeyScope(newScope): re-keys the CURRENT conversation
(cache write + synchronous conversationScope flip) so the #2450 scope gate
holds through the host's ?package= navigate — no pane remount mid-stream.
- Legacy-scope fallback read (legacyScope/adoptLegacy): an app-scoped visit
whose key was never cached adopts the product-only thread iff the host's
predicate confirms the thread is bound to that app (pre-A1.b migration).
Failing fetch degrades to a plain miss; the legacy key is never cleared
(dock/FAB keep resolving through it).
- AiChatPage: ChatPane reports the binding (post-URL-mirror only — single-
navigator rule); the page re-keys and puts ?package= on the URL. Reload
without ?package= self-heals from hydrated history.
- A1.a chip is now a switcher: apps (by package) → their Edit-with-AI
thread; New app → ?new=1 fresh unbound draft.
Client-side only: conversation scope keying is a per-(user,scope)
localStorage cache; the server needs no change.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercelBot commented Jul 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectuiIgnoredIgnoredJul 13, 2026 9:42pm

Request Review

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Jul 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

❌ Console Performance Budget

MetricValueBudget
Main entry (gzip)** KB**KB
Entry file``
StatusFAIL

📦 Bundle Size Report

PackageSizeGzipped
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)21.70KB4.21KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.12KB3.41KB
auth (LoginForm.js)16.53KB4.84KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.63KB2.15KB
auth (SocialSignInButtons.js)8.89KB3.61KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)29.64KB7.14KB
auth (createAuthenticatedFetch.js)3.93KB1.55KB
auth (index.js)1.83KB0.79KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)4.86KB0.85KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)18.38KB4.49KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)3.65KB1.42KB
collaboration (PresenceProvider.js)2.42KB0.96KB
collaboration (index.js)1.25KB0.53KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
core (index.js)1.65KB0.59KB
create-plugin (index.js)9.28KB2.98KB
data-objectstack (index.js)113.70KB28.15KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.32KB1.77KB
i18n (index.js)2.46KB0.96KB
i18n (pickLocalized.js)1.31KB0.67KB
i18n (provider.js)5.37KB1.72KB
i18n (useObjectLabel.js)21.15KB4.68KB
i18n (useSafeTranslation.js)2.68KB0.98KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.74KB
mobile (index.js)1.50KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)4.42KB1.27KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.63KB
mobile (useSpecGesture.js)1.77KB0.77KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)5.09KB1.84KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)3.46KB1.03KB
permissions (evaluator.js)4.00KB1.23KB
permissions (index.js)0.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
permissions (usePermissions.js)1.50KB0.70KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.55KB0.67KB
providers (UploadProvider.js)11.71KB3.53KB
providers (index.js)0.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)3.19KB1.38KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)18.23KB5.97KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)0.79KB0.43KB
sdui-parser (codegen.js)4.09KB1.74KB
sdui-parser (index.js)2.16KB0.94KB
sdui-parser (parse.js)10.04KB2.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)4.69KB1.48KB
tenant (TenantContext.js)0.31KB0.25KB
tenant (TenantGuard.js)1.04KB0.43KB
tenant (TenantProvider.js)2.76KB0.98KB
tenant (TenantScopedQuery.js)0.77KB0.44KB
tenant (index.js)0.75KB0.38KB
tenant (resolver.js)2.64KB0.76KB
tenant (useTenant.js)0.50KB0.32KB
tenant (useTenantBranding.js)0.62KB0.39KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)0.77KB0.41KB
types (disclosure.js)0.20KB0.18KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (index.js)1.54KB0.68KB
types (layout.js)0.20KB0.18KB
types (mobile.js)0.20KB0.18KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.26KB1.96KB
types (tenant.js)0.20KB0.18KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)0.75KB0.46KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)26.5 KB350 KB
Entry fileindex-DDpjdzl5.js
StatusPASS

📦 Bundle Size Report

PackageSizeGzipped
app-shell (index.js)7.84KB2.85KB
app-shell (runtime-config.js)7.56KB2.37KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)7.57KB2.97KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)21.70KB4.21KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.12KB3.41KB
auth (LoginForm.js)16.53KB4.84KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.63KB2.15KB
auth (SocialSignInButtons.js)8.89KB3.61KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)29.64KB7.14KB
auth (createAuthenticatedFetch.js)3.93KB1.55KB
auth (index.js)1.83KB0.79KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)4.86KB0.85KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)18.38KB4.49KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)3.65KB1.42KB
collaboration (PresenceProvider.js)2.42KB0.96KB
collaboration (index.js)1.25KB0.53KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)441.58KB95.30KB
core (index.js)1.65KB0.59KB
create-plugin (index.js)9.28KB2.98KB
data-objectstack (index.js)113.70KB28.15KB
fields (index.js)202.54KB49.50KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.32KB1.77KB
i18n (index.js)2.46KB0.96KB
i18n (pickLocalized.js)1.31KB0.67KB
i18n (provider.js)5.37KB1.72KB
i18n (useObjectLabel.js)21.15KB4.68KB
i18n (useSafeTranslation.js)2.68KB0.98KB
layout (index.js)38.45KB10.67KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.74KB
mobile (index.js)1.50KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)4.42KB1.27KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.63KB
mobile (useSpecGesture.js)1.77KB0.77KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)5.09KB1.84KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)3.46KB1.03KB
permissions (evaluator.js)4.00KB1.23KB
permissions (index.js)0.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
permissions (usePermissions.js)1.50KB0.70KB
plugin-ai (index.js)15.71KB3.79KB
plugin-calendar (index.js)45.12KB12.34KB
plugin-charts (index.js)46.31KB13.06KB
plugin-chatbot (index.js)176.18KB42.05KB
plugin-dashboard (index.js)108.35KB26.87KB
plugin-designer (index.js)213.94KB43.03KB
plugin-detail (index.js)210.10KB50.68KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)104.26KB25.24KB
plugin-gantt (index.js)141.17KB35.08KB
plugin-grid (index.js)171.84KB45.38KB
plugin-kanban (index.js)48.16KB12.94KB
plugin-list (index.js)98.52KB23.24KB
plugin-map (index.js)16.80KB5.24KB
plugin-markdown (index.js)13.65KB4.67KB
plugin-report (index.js)37.82KB9.96KB
plugin-timeline (index.js)25.37KB7.20KB
plugin-tree (index.js)8.21KB2.76KB
plugin-view (index.js)85.51KB20.81KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.55KB0.67KB
providers (UploadProvider.js)11.71KB3.53KB
providers (index.js)0.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)3.19KB1.38KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)18.23KB5.97KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)0.79KB0.43KB
sdui-parser (codegen.js)4.09KB1.74KB
sdui-parser (index.js)2.16KB0.94KB
sdui-parser (parse.js)10.04KB2.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)4.69KB1.48KB
tenant (TenantContext.js)0.31KB0.25KB
tenant (TenantGuard.js)1.04KB0.43KB
tenant (TenantProvider.js)2.76KB0.98KB
tenant (TenantScopedQuery.js)0.77KB0.44KB
tenant (index.js)0.75KB0.38KB
tenant (resolver.js)2.64KB0.76KB
tenant (useTenant.js)0.50KB0.32KB
tenant (useTenantBranding.js)0.62KB0.39KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)0.77KB0.41KB
types (disclosure.js)0.20KB0.18KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (index.js)1.54KB0.68KB
types (layout.js)0.20KB0.18KB
types (mobile.js)0.20KB0.18KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.26KB1.96KB
types (tenant.js)0.20KB0.18KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)0.75KB0.46KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

…ed history on a same-conversation empty re-read
Live verification caught a race the design review missed: re-keying the
moment the binding draft lands MID-STREAM lets the scope-change re-resolve
read the conversation before the server persists the turn (persistence is
at turn COMPLETION), and a reconcile can then replace the live thread with
that empty not-yet-persisted history — the pane blanked until reload.
- ChatPane's bind effect now also waits for isLoading to drop: the re-key
runs against a fully persisted turn (and 'bind at build completion' is
truer to the named-on-first-save idiom anyway). Re-verified live: the
thread stays visible through the bind, URL gains ?package=, and the
Edit-with-AI entry resumes the same conversation with history.
- useChatConversation's activeId branch no longer overwrites non-empty
hydrated messages with an EMPTY read of the SAME conversation (a later
remount would hydrate from that and render a blank thread); an empty
read of a DIFFERENT conversation still replaces as before. Unit-tested.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@os-zhuang

Copy link
Copy Markdown
ContributorAuthor

Live browser proof (local cloud rig, run-stack.sh --with-ui --prod-like --seed, console overlaid from this branch)

1. Bind-on-create (the magic flow), reproduced end-to-end. Fresh unbound /ai/build?new=1 → conversation conv_7f020f32… minted, chip = "✨ New app" → built a tiny contacts app (propose → 开始搭建 → apply). When the turn completed, the conversation re-keyed in place: URL became /ai/build/conv_7f020f32…?package=app.hgp9, chip flipped to 📦 Contacts, thread stayed fully visible (no remount/blank), and localStorage held the SAME id under both …:build and …:app:app.hgp9:build.

2. The continuity bug is fixed. Left the surface, re-entered via the Edit-with-AI shape (/ai/build?package=app.hgp9): the same conversation (conv_7f020f32…) resumed with the full build history visible — previously this minted a separate empty thread.

3. Legacy fallback (pre-A1.b migration). Deleted the app:app.hgp9:build cache key (simulating a browser that bound the thread before this PR), kept the product-only key → /ai/build?package=app.hgp9adopted the product-only thread via the history predicate: same id resumed, key rewritten. An unbound/foreign thread is not hijacked (predicate must match; unit-tested).

4. Switcher. Chip opens "Build conversations by app" (apps deduped by package, bound one checked, ✨ New app at the bottom); clicking Tiny Bookmarks switched to that app's own thread (conv_5fc1c755…?package=app.slqe) with its history. Bare /ai/build still resumes as before.

Fix found by this verification (second commit): re-keying the instant the draft landed mid-stream raced turn persistence — the scope-change re-resolve read the conversation before the server persisted the turn, and a reconcile could replace the live thread with that empty history (pane blanked until reload, reproduced twice). The bind now waits for the turn to go idle, and useChatConversation never overwrites non-empty hydrated messages with an empty same-conversation re-read. Re-verified live after the fix: no blank at any point.

58 tests green across useChatConversation (29, incl. 10 new), chatScope, deriveBoundPackageId, useDeferredFirstSend, AiChatPage.hydration, useObjectChat.handoffContext; tsc --noEmit clean.

…schel-fc7c63
# Conflicts:
#	packages/app-shell/src/console/ai/AiChatPage.tsx
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)26.6 KB350 KB
Entry fileindex-Bb-0V9e5.js
StatusPASS

📦 Bundle Size Report

PackageSizeGzipped
app-shell (index.js)7.84KB2.85KB
app-shell (runtime-config.js)7.56KB2.37KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)7.57KB2.97KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)21.70KB4.21KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.12KB3.41KB
auth (LoginForm.js)17.12KB5.00KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.63KB2.15KB
auth (SocialSignInButtons.js)9.60KB3.89KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)30.17KB7.28KB
auth (createAuthenticatedFetch.js)3.93KB1.55KB
auth (index.js)1.83KB0.79KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)4.86KB0.85KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)18.38KB4.49KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)3.65KB1.42KB
collaboration (PresenceProvider.js)2.42KB0.96KB
collaboration (index.js)1.25KB0.53KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)441.58KB95.30KB
core (index.js)1.65KB0.59KB
create-plugin (index.js)9.28KB2.98KB
data-objectstack (index.js)113.70KB28.15KB
fields (index.js)202.54KB49.50KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.32KB1.77KB
i18n (index.js)2.46KB0.96KB
i18n (pickLocalized.js)1.31KB0.67KB
i18n (provider.js)5.37KB1.72KB
i18n (useObjectLabel.js)21.15KB4.68KB
i18n (useSafeTranslation.js)2.68KB0.98KB
layout (index.js)38.45KB10.67KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.74KB
mobile (index.js)1.50KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)4.42KB1.27KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.63KB
mobile (useSpecGesture.js)1.77KB0.77KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)5.09KB1.84KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)3.46KB1.03KB
permissions (evaluator.js)4.00KB1.23KB
permissions (index.js)0.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
permissions (usePermissions.js)1.50KB0.70KB
plugin-ai (index.js)15.71KB3.79KB
plugin-calendar (index.js)45.12KB12.34KB
plugin-charts (index.js)46.31KB13.06KB
plugin-chatbot (index.js)176.18KB42.05KB
plugin-dashboard (index.js)108.35KB26.87KB
plugin-designer (index.js)213.94KB43.03KB
plugin-detail (index.js)210.10KB50.68KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)104.26KB25.24KB
plugin-gantt (index.js)141.17KB35.08KB
plugin-grid (index.js)171.84KB45.38KB
plugin-kanban (index.js)48.16KB12.94KB
plugin-list (index.js)98.52KB23.24KB
plugin-map (index.js)16.80KB5.24KB
plugin-markdown (index.js)13.65KB4.67KB
plugin-report (index.js)37.82KB9.96KB
plugin-timeline (index.js)25.37KB7.20KB
plugin-tree (index.js)8.21KB2.76KB
plugin-view (index.js)85.51KB20.81KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.55KB0.67KB
providers (UploadProvider.js)11.71KB3.53KB
providers (index.js)0.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)3.19KB1.38KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)18.23KB5.97KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)0.79KB0.43KB
sdui-parser (codegen.js)4.09KB1.74KB
sdui-parser (index.js)2.16KB0.94KB
sdui-parser (parse.js)10.04KB2.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)4.69KB1.48KB
tenant (TenantContext.js)0.31KB0.25KB
tenant (TenantGuard.js)1.04KB0.43KB
tenant (TenantProvider.js)2.76KB0.98KB
tenant (TenantScopedQuery.js)0.77KB0.44KB
tenant (index.js)0.75KB0.38KB
tenant (resolver.js)2.64KB0.76KB
tenant (useTenant.js)0.50KB0.32KB
tenant (useTenantBranding.js)0.62KB0.39KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)0.77KB0.41KB
types (disclosure.js)0.20KB0.18KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (index.js)1.54KB0.68KB
types (layout.js)0.20KB0.18KB
types (mobile.js)0.20KB0.18KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.26KB1.96KB
types (tenant.js)0.20KB0.18KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)0.75KB0.46KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@os-zhuang
os-zhuang merged commit 76eadf8 into mainJul 13, 2026
10 checks passed
@os-zhuang
os-zhuang deleted the claude/determined-herschel-fc7c63 branch July 13, 2026 21:53
os-zhuang added a commit that referenced this pull request Jul 14, 2026
…count) (#2474)
The A1.b package switcher (#2466) listed every app with a _packageId,
including code-delivered platform built-ins (setup / account,
com.objectstack.*). Selecting one deep-linked /ai/build?package=<builtin>
to a package the build agent can't author.
Filter on the reserved com.objectstack.* package namespace — the only
signal that reliably distinguishes built-ins on the /meta/app LIST
response: _packageId is grafted onto every list item, whereas
managedBy/source are sys_metadata row columns the list handler doesn't
copy onto the item body, and the lock/editable envelope is single-GET
only. New exported predicate isPlatformBuiltinApp; unit-tested.
Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationtests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@os-zhuang