Skip to content

feat(app-shell,i18n): Setup Packages is the one installed list — Source column, marketplace row actions, ?source= filter (objectui#12675) - #12722

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-12675-packages-source
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-12675-packages-source

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #12675
Clause-②: yes (narrowing)

Setup → Packages is now the one list of what is installed (ruling B on objectstack-ai/objectstack#23892, record 6216295104).

What changed

  • Source column. Every row reads Code, Marketplace or Authored, from a closed set (views/metadata-admin/packageSource.ts). Each value comes from a named signal:

    • Authored: the served row's writable verdict is true (objectstack#14375).
    • Marketplace: the row is not writable, and the marketplace slice lists its id. That is the list the Installed Apps page read: the control plane's list when cloud-connected, otherwise this runtime's install-local list, read strictly.
    • Code: every other non-writable row.

    The list is refused by name, with no rows drawn, in three cases: a row with no boolean writable, a writable row that the marketplace also lists, and a marketplace list that cannot be read while the capability is on.

  • Marketplace row actions. The Installed Apps list offered two actions: Details and Uninstall (Uninstall on local installs only). Both now sit on Packages rows whose Source is Marketplace, in console/marketplace/MarketplaceRowActions.tsx. They reuse uninstallLocal and the same pack sentences, and Uninstall asks for confirmation in-app.

    • Shown only when features.installLocal is on and the viewer is a workspace admin; these are the two gates Installed Apps had.
    • Update and the sample-data Re-seed / Purge menu were never on Installed Apps. They stay on the package page that Details opens, so no second copy exists.
    • An install the runtime refused to load still gets a row, with its Not loaded reason and Uninstall.
  • Filter spelling, for cloud-connection: the "Installed Apps" entry opens Setup Packages filtered to Source = marketplace (ruling B on #23892; after the objectui card lands and the pin moves) objectstack#23933 to copy: /apps/APP/component/developer/packages?source=marketplace. A Setup nav item reaches the same URL with { type: 'component', componentRef: 'developer:packages', params: { source: 'marketplace' } }, because the sidebar sends a component item's params as the query string. The allowed values are code, marketplace and authored. An unknown, empty or repeated value is refused by name.

  • Installed Apps entries. The marketplace:installed-list widget, which the plugin's marketplace_installed page renders, now redirects to the filtered Packages URL. So does the legacy system/marketplace/installed route. The InstalledList body is gone.

  • Language packs. Seven marketplace.* keys that only the InstalledList body read are removed from all ten packs. New Packages copy goes in the metadata-admin designer table (en and zh).

  • Untouched: the PackagesPage header (feat(app-shell): one page header for every Setup page — sys_* lists, metadata types, settings and component pages (objectui#12606) #12662 is rewriting it), objectstack's cloud-connection package, and the spec.

Narrowing, declared for contract review

  • Removed from @object-ui/i18n in all ten packs: marketplace.installedTitle, installedSubtitle, installedEmpty, installedAt, installedBy, installedPackageId and cachedAs.
  • The marketplace:installed-list widget and the MarketplaceInstalledPage export now redirect instead of drawing a list.
  • No export, widget registration or route is removed.

The follow-up after objectstack-ai/objectstack#23933 retires the widget registration, both routes and the export, and points MarketplacePage's Installed (N) button straight at the Packages URL.

Tests

At head 681c066, after merging origin/main f8267df: app-shell type-check passes, and the vitest run over Packages, the marketplace dir, the i18n package and the route and parity suites gives Test Files 133 passed, Tests 2025 passed, 13 skipped.

New pins:

  • PackagesPage.source-12675.test.tsx (14 tests): plugin present; plugin absent; non-admin; unknown, conflicting or unreadable origin refused; unknown, empty or repeated filter refused; widget and legacy route redirect.
  • MarketplaceRowActions.installedAppsPins.test.tsx (27 tests): the 11645 not-loaded, 12610 kernel-tooltip and 7611 walled-uninstall pins, carried onto the rows.

Ablations, each red and each restored to the HEAD blob:

  • A1, unknown-writable refusal removed: 1 failed.
  • A2, capability gate removed: 1 failed.
  • A3, filter removed: 1 failed.
  • A4, unknown filter accepted: 2 failed.
  • A5, widget renders nothing: 2 failed.
  • A6, tolerant listing read: 1 failed.
  • A7, conflict refusal removed: 1 failed.
  • A8, not-loaded rows dropped: 8 failed.

Builds: the app-shell and console closure builds and the console vite build all pass.

Screenshots

At 1280 px against a published @objectstack 18.0.0-next.2 showcase backend, on branch claude/issue-12675-evidence under evidence/12675/. The before-* files are from main and the after-* files from this branch. They cover Packages, the marketplace filter, an unknown filter, the plugin's Installed Apps page and the legacy route.

Acceptance notes

  • The row signals are joined because the served row declares no origin key. The contract-first follow-up is a declared source key on the served row; that is objectstack work the seat files.
  • Pre-existing, not changed here: the Scope badge reads Writable for any row with no scope, including a marketplace install the server marks not writable (see before-packages.png).
  • listLocalInstalls still treats any failure as an empty list for the marketplace pages. Only the Source read uses the new strict fetchLocalInstalls.

Provenance: built by the cloud session session_01L1BStZ37S5WzHGfEgk5NQJ (claim 6217043127) and opened by the domain:ui seat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) from that session's final message, because a cloud session cannot open a PR from its container. The seat replaced the dev's own footer line with this line.


Generated by Claude Code

…e marketplace row actions

The Packages list gains a Source column with the closed values code /
marketplace / authored, read from the row's `writable` verdict joined with
the marketplace slice's installed list; a row neither signal can place is
refused by name. Rows whose Source is marketplace carry the actions the
Installed Apps list had (Details, Uninstall) when the install-local
capability is present. `?source=` filters the list; an unknown or repeated
value is refused. The `marketplace:installed-list` widget and the legacy
Installed Apps route now open Packages filtered to Source = marketplace.

Claude-Session: https://claude.ai/code/session_01L1BStZ37S5WzHGfEgk5NQJ
Co-authored-by: Claude <noreply@anthropic.com>
…s; carry the Installed Apps pins onto them

The Installed Apps list's not-loaded, kernel-note and walled-refusal pins now
read the Packages marketplace rows; its install-date face and the seven pack
keys only it read leave with its body.

Claude-Session: https://claude.ai/code/session_01L1BStZ37S5WzHGfEgk5NQJ
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 1 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/12288-marketplace-install-mode.md

  • names marketplaceApi.ts → packages/app-shell/src/console/marketplace/marketplaceApi.ts — edited by this change

    Clause-②: yes (widening): @object-ui/i18n's ten locale packs gain nine keys under marketplace.install (mode.label, mode.managed, mode.managedHint, mode.unmanaged, mode.unmanagedHint, mode.required, unmanagedSuccess, unmanagedStrippedLocks, unmanagedIgnored). Nothing else on either package entry changes. installLocal's new optional installMode input, getDeclaredInstallModes and the LocalInstallMode / LocalInstallResult types live in marketplaceApi.ts, which ships inside dist/ but is not exported from the @object-ui/app-shell entry. MarketplacePackagePage, which is exported, keeps its props.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with 96fa4b9bc (merge-base with origin/main): 25 file(s) changed outside .changeset/, read against 593 pending declaration(s) that publish a body (613 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 71 chunks) 3120.7 KB 3744.1 KB
Main entry chunk (gzip) 66.0 KB 350 KB
Entry file index-Dm4KrcCg.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 21.42KB 7.85KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.39KB 6.02KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 597.81KB 144.28KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.96KB 69.45KB
fields (index.js) 290.81KB 74.35KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 40.67KB 11.85KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 54.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.89KB 48.13KB
plugin-dashboard (index.js) 146.15KB 39.55KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 263.43KB 69.61KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 180.92KB 46.73KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 270.35KB 74.86KB
plugin-kanban (index.js) 59.42KB 18.48KB
plugin-list (index.js) 132.91KB 34.06KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 93.43KB 23.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 1.13KB 0.65KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.78KB 2.70KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 681c066b5c387e776ad4930071e966a7db48a566
Local-runs: none
Scope: packages/app-shell/src/console/marketplace/InstalledListWidget.tsx, packages/app-shell/src/console/marketplace/MarketplaceInstalledPage.tsx, packages/app-shell/src/console/marketplace/MarketplaceRowActions.tsx, packages/app-shell/src/console/marketplace/tests/InstalledListWidget.kernelNoteTooltip-12610.test.tsx, packages/app-shell/src/console/marketplace/tests/InstalledListWidget.notLoaded-11645.test.tsx, packages/app-shell/src/console/marketplace/tests/MarketplaceRowActions.installedAppsPins.test.tsx, packages/app-shell/src/console/marketplace/tests/marketplaceDates.displayLocale-10331.test.tsx, packages/app-shell/src/console/marketplace/tests/walledCatalogPackageRefusal-7611.test.tsx, packages/app-shell/src/console/marketplace/marketplaceApi.ts, packages/app-shell/src/views/metadata-admin/PackagesPage.confirmFlows-11784.test.tsx, packages/app-shell/src/views/metadata-admin/PackagesPage.source-12675.test.tsx, packages/app-shell/src/views/metadata-admin/PackagesPage.tsx, packages/app-shell/src/views/metadata-admin/PackagesPage.walledCatalogRefusal-7611.test.tsx, packages/app-shell/src/views/metadata-admin/i18n.ts, packages/app-shell/src/views/metadata-admin/packageSource.ts, packages/i18n/src/locales/ar.ts, packages/i18n/src/locales/de.ts, packages/i18n/src/locales/en.ts, packages/i18n/src/locales/es.ts, packages/i18n/src/locales/fr.ts, packages/i18n/src/locales/ja.ts, packages/i18n/src/locales/ko.ts, packages/i18n/src/locales/pt.ts, packages/i18n/src/locales/ru.ts, packages/i18n/src/locales/zh.ts + packages/app-shell/src/index.ts, packages/app-shell/src/console/AppContent.tsx, packages/app-shell/src/console/marketplace/MarketplacePage.tsx, packages/app-shell/src/services/builtinComponents.tsx, packages/app-shell/src/runtime-config.ts, packages/app-shell/src/urlParams.ts, packages/layout/src/NavigationRenderer.tsx, .changeset/12288-marketplace-install-mode.md, .changeset/config.json, objectstack packages/cloud-connection/src/marketplace-ui.ts, objectstack packages/cloud-connection/src/marketplace-install-local-plugin.ts, objectstack packages/runtime/src/domains/packages.ts, objectstack packages/metadata-protocol/src/package-writability.ts, objectstack packages/spec/src/kernel/package-registry.zod.ts, objectstack packages/spec/src/api/package-api.zod.ts, objectstack scripts/pm/record-recognisers.mjs, objectstack scripts/pm/clause2-line.mjs

Face: narrowing — seven published marketplace.* keys leave all ten @object-ui/i18n packs, and the published marketplace:installed-list widget and the exported MarketplaceInstalledPage redirect instead of drawing a list — judged together with the widening half (the Source column, the marketplace row actions, and the ?source= filter spelling objectstack-ai/objectstack#23933 binds to), which is why the PR body carries Clause-②: yes. Inputs: card #12675 with every comment (claim 6217043127, dev report 6218334568), the ruling 6216295104 on objectstack-ai/objectstack#23892, the PR body and file list, the net diff of the head against its merge-base with origin/main (f8267df93a; the head's merge of main is excluded), and the check-runs on the head. Check-runs on the head: every run completed with conclusion success — Lint, Type Check, Build and E2E, Build Docs, Bundle Analysis, Repo Gates, Line Citation Gate, Governed Surface Queue Guard, Changeset Declaration, Changeset Claim Re-read, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Overwrite Report, Test, Test (dist pins), Test shards 1 to 16 of 16, Live E2E (informational), label — and the coverage matrix and dependabot runs read skipped by their own conditions. None failed. Those conclusions are the gate verdicts; nothing was built, run or re-run here.

① Derived judgments

Narrowing half

  • Removal of marketplace.installedTitle, installedSubtitle, installedEmpty, installedAt, installedBy, installedPackageId and cachedAs from all ten packs — RIGHT. The readers at the merge-base were exactly the retired list body (InstalledListWidget.tsx read installedEmpty, installedAt, installedBy, installedPackageId, cachedAs), the retired page header (MarketplaceInstalledPage.tsx read installedTitle, installedSubtitle) and the two deleted widget tests. At the head no code, test or doc in objectui reads any of the seven (the remaining installedAt / installedBy hits are wire fields of the install-local entry, not pack keys), and objectstack's source tree reads none. Each pack loses the same seven, so key parity across the ten holds. Two of the removed values carried inline markup rendered through dangerouslySetInnerHTML; both sinks leave with them. The marketplace pack namespace only shrinks (ADR-0060 rule 3). Outside this repo the key set is a published surface of @object-ui/i18n; the changeset names each key and the host consequence (the key comes back instead of a sentence) — the one line it still lacks is in ②.
  • marketplace:installed-list now renders a replacing Navigate to packagesHref(base, 'marketplace'), and its registration (namespace: 'app-shell', inputs: []) is unchanged — RIGHT. objectstack's packages/cloud-connection/src/marketplace-ui.ts still composes the served marketplace_installed page from { type: 'marketplace:installed-list' }, so that page resolves at this head (pinned: ComponentRegistry.get returns a function and lands on /apps/setup/component/developer/packages?source=marketplace). Until objectstack#23933 retargets the entry, the served page's own title block draws for an instant before the redirect — cosmetic, and the follow-up removes it.
  • MarketplaceInstalledPage is still exported (src/index.ts) and both system/marketplace/installed routes stay (AppContent.tsx, the no-active-app block and the app block) — RIGHT. Each redirect keeps the app segment, and with no app segment lands on /apps/setup, a spelling AppContent already recognises. MarketplacePage's "Installed (N)" button still targets the legacy route, so it reaches Packages through one redirect; that file is feat(app-shell): one page header for every Setup page — sys_* lists, metadata types, settings and component pages (objectui#12606) #12662's and the claim kept it out of this PR.
  • The two deleted InstalledListWidget.* test files — RIGHT under the duplicate rule. Every assertion has a counterpart in MarketplaceRowActions.installedAppsPins.test.tsx at a layer at least as close (the real PackagesPage and the real marketplaceApi over one stubbed wire): the 11645 badge and reason, the narrowed caller, the loaded control, DELETE for the manifest id with the re-read listing dropping the row (two GETs), the not-loaded and loaded confirm and result sentences, an unknown refusal code named; the 12610 tooltip, accessible description, sr-only copy, no note on a not-loaded row, no note with no install, all ten packs plain text; the 7611 walled refusal shows the door's sentence and the row stays. The 10331 InstalledList date face is dropped because no install date is drawn any more (the MarketplacePage face stays pinned), and the 7611 InstalledList row case moved into the carried file.

Widening half

  • The Source derivation (packageSource.ts) — RIGHT. Closed set code, marketplace, authored. writable === true gives authored; false and listed by the marketplace gives marketplace; false and not listed gives code; a non-boolean writable is refused as PACKAGE_SOURCE_UNKNOWN and a writable row the marketplace also lists as PACKAGE_SOURCE_CONFLICT; a refusal names the id and replaces the list with no rows (pinned). On the objectstack side, withWritableVerdict stamps writable on every GET /packages row after the projection (packages/runtime/src/domains/packages.ts, pinned there by packages-serializable-response.test.ts), and isWritablePackage (packages/metadata-protocol/src/package-writability.ts) answers false for every engine.manifests member — a booted code package and an install-local install registered through registerApp alike — and for the read-only scopes, true otherwise. So the join is exact today and each value traces to one named signal. InstalledPackageSchema (package-registry.zod.ts) and the GET /packages response in package-api.zod.ts declare neither writable nor an origin key: the read is of a served, undeclared key, and the sound interim form of that read — strict, absence refused, no alias and no ?? in the consumer — is what the diff has, with the contract-first half filed as packages API: the served installed-package row declares no origin. Declare a closed source (code / marketplace / authored); objectui's Packages Source column joins the undeclared writable with a second read today objectstack#23972 (open). With the capability off, nothing is read from the marketplace and every non-writable row reads code.
  • The marketplace list read — RIGHT. readMarketplaceInstalls takes the control plane's list when connected, otherwise the strict fetchLocalInstalls (a non-ok answer or one with no items array throws); the Packages load joins the two reads with Promise.all, so an unreadable listing refuses the whole list instead of relabelling installs as code (pinned). The install-local listing door's floor is authenticated → 200 with narrowed fields, so a non-admin Packages viewer still gets rows; listInstalledPackages folds a non-ok control-plane answer into connected: false. listLocalInstalls keeps its tolerant shape for the marketplace pages, as the acceptance notes say. A cloud-listed install with no registry row gets a row with no status and Details only.
  • The row-action gates — RIGHT. The Actions column renders only when getRuntimeConfig().features.installLocal and useWorkspaceAdminStatus().isAdmin both hold, the two gates Installed Apps had (pinned for a non-admin and for the capability absent, the latter also asserting that no marketplace request is made); Uninstall only when the list is this runtime's ledger; the confirm is the in-app AlertDialog; stopPropagation keeps the row's detail sheet closed (pinned). A refused install with no registry row keeps its row, its Not loaded reason and its Uninstall (pinned).
  • No second copy — RIGHT. MarketplaceRowActions calls the existing uninstallLocal with the existing pack sentences; Update and Re-seed / Purge stay in MarketplacePackagePage, reached by Details.
  • ?source= — RIGHT. source is not in RESERVED_URL_PARAMS (urlParams.ts); readSourceFilter over getAll('source') refuses an unknown value, the empty value and a repeated param by name, with no rows drawn (pinned for all three). The nav-item spelling the changeset publishes holds in code: resolveHref's component case (packages/layout/src/NavigationRenderer.tsx) serialises item.params as the query string, so { type: 'component', componentRef: 'developer:packages', params: { source: 'marketplace' } } yields /apps/APP/component/developer/packages?source=marketplace.
  • The pending changeset .changeset/12288-marketplace-install-mode.md — still TRUE at this head: marketplaceApi.ts gains fetchLocalInstalls and readMarketplaceInstalls, src/index.ts still exports nothing from it, and the nine marketplace.install.* keys are untouched.
  • Carried note, not this PR's defect: marketplace.installedAdditiveNote, now the row Uninstall's tooltip, is the sentence objectui#12684 reports as stale; the carry is faithful and that card owns the fix.

② Semver level

  • @object-ui/i18n: minor — matches objectui's rule that a breaking change in the fixed group is minor with its breaking meaning in the body; the body names the seven keys, the one reader that left, and the host consequence. Gap to close while the file is open: the one-line fix for a host that still reads one of them (carry the sentence in the host's own bundle, or drop the read).
  • @object-ui/app-shell: minor — matches: a new column, a new filter spelling and a changed render of a published widget and export, each stated in the body. Wording to add: with features.installLocal off no row reads Marketplace, so a cloud-connected environment's control-plane installs read Code there (the dev's question 5; the declared key of objectstack#23972 removes the case).
  • The Clause-②: line — WRONG as committed, and this is the verdict's finding. The PR body carries Clause-②: yes with no arm, and neither committed changeset carries the line. The fleet's one reader of that line (readClause2Line in scripts/pm/clause2-line.mjs, read by reviewFace in scripts/pm/record-recognisers.mjs) keys the narrowing face on a (narrowing) arm written at the start of a line on the PR body or on a committed changeset — Clause-②: yes (narrowing) for a diff that widens and narrows, as this one does. Read off this tree, the declaration is the declaration face: a CONTRACT_REVIEW_TIER record does not stand on that face, and the narrowing the body declares in prose is invisible to a reader that is read off the committed tree and never off a seat's statement. Remedy, one line per carrier: Clause-②: yes (narrowing) at the start of a line in the PR body and in .changeset/12675-installed-apps-keys.md (the narrowing's carrier; the app-shell changeset may carry it too, since the widget and the export change what they render). The changeset edit moves the head, so the record is re-rendered on the new head; the code half above needs no re-reading unless the diff changes.

③ Boundary flags

Five open_questions in the dev report 6218334568; the seat's answers on the card are A, A, A, declared, A.

  1. Source signal contract → A. Answered. packages API: the served installed-package row declares no origin. Declare a closed source (code / marketplace / authored); objectui's Packages Source column joins the undeclared writable with a second read today objectstack#23972 is filed and open; the interim join is judged sound in ①.
  2. Update and Re-seed / Purge as row controls → A. Answered. Measured at the merge-base, the Installed Apps body carried Details and Uninstall only; ruling item 2's "retires once the filtered view serves its actions" is met, and item 1's longer list is served one click away through Details with no second copy. B stays a follow-up card if the maintainer wants it.
  3. Retirement follow-up → A (one objectui card, Blocked-by cloud-connection: the "Installed Apps" entry opens Setup Packages filtered to Source = marketplace (ruling B on #23892; after the objectui card lands and the pin moves) objectstack#23933). Answered; no such card was located among objectui's open issues at this read, so the filing is a pending seat act, not a PR defect.
  4. Narrowing → declared, this review. Answered in substance; the committed spelling of the declaration is the ② finding.
  5. The installLocal-off edge → A. Answered; acceptable as a case not measured to exist, with the changeset wording in ② making the behaviour explicit.

Dev flags: the class-a Scope badge finding is filed as objectui#12723 (open); the tolerant listLocalInstalls on the marketplace pages is in the PR's acceptance notes; the two fixtures that gained writable: true are consistent with every served row carrying the verdict. Nothing escalated.

Implemented-by: claude/issue-12675-packages-source
Reviewed-by: session_011K9g23W67dy2zwnyzaoB6o

VERDICT: FAIL

The code half passes on every derived judgment; the verdict fails on the declaration alone. Rendered 2026-10-16T15:54Z, read-only.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

REWORK round 1 → PR #12722 · domain:ui seat 1 · session_011K9g23W67dy2zwnyzaoB6o · 2026-10-16T15:55Z

The contract review 6219326691 (CONTRACT_REVIEW_TIER) failed on head 681c066 for the declaration only. Every derived judgment on the code passed, so this round touches no code.

Patch round on the same claim (6217043127), same cloud session, same branch:

  1. The declaration line. The fleet's reader of the line (readClause2Line, read by reviewFace) keys the narrowing face on a (narrowing) arm at the start of a line, on the PR body or on a committed changeset. This PR both widens and narrows, so it is spelled Clause-②: yes (narrowing).
    • Add that exact line, at the start of a line, to .changeset/12675-installed-apps-keys.md (the narrowing's carrier) and to .changeset/12675-packages-source.md (the widget and the export change what they render).
    • Frontmatter stays untouched. The seat fixes the PR body's own line.
  2. .changeset/12675-installed-apps-keys.md: add the one-line fix for a host that still reads one of the seven removed keys: carry the sentence in the host's own bundle, or drop the read.
  3. .changeset/12675-packages-source.md: add one sentence. With features.installLocal off, no row reads Marketplace, so in such an environment control-plane installs read Code; packages API: the served installed-package row declares no origin. Declare a closed source (code / marketplace / authored); objectui's Packages Source column joins the undeclared writable with a second read today objectstack#23972's declared key removes that case.
  4. Push once pnpm check:changeset-claims, pnpm changeset:check and node scripts/check-changeset-presence.mjs are green on the new head. No merge of main is needed: the PR reads clean.

File surface for this round: the two .changeset/12675-*.md files only, prose. The seat re-runs the contract review on the new head; the review states that the code half needs no re-reading.

Report back with a delta os-dev-report (head sha, gates with exit codes).


Generated by Claude Code

…e installLocal-off Code case (objectui#12675)

Claude-Session: https://claude.ai/code/session_01L1BStZ37S5WzHGfEgk5NQJ
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 74 chunks) 3121.6 KB 3744.1 KB
Main entry chunk (gzip) 66.0 KB 350 KB
Entry file index-B0ck51uE.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 21.42KB 7.85KB
app-shell (runtime-config.js) 22.59KB 7.89KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.39KB 6.02KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 41.19KB 11.12KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 597.81KB 144.28KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.96KB 69.45KB
fields (index.js) 290.81KB 74.35KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 40.67KB 11.85KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 54.94KB 16.05KB
plugin-charts (index.js) 84.97KB 23.36KB
plugin-chatbot (index.js) 201.89KB 48.13KB
plugin-dashboard (index.js) 146.15KB 39.55KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 263.43KB 69.61KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 180.28KB 46.60KB
plugin-gantt (index.js) 178.36KB 45.08KB
plugin-grid (index.js) 270.35KB 74.86KB
plugin-kanban (index.js) 59.42KB 18.48KB
plugin-list (index.js) 132.91KB 34.06KB
plugin-map (index.js) 27.07KB 8.96KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 93.43KB 23.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 120.23KB 39.46KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 1.13KB 0.65KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.78KB 2.70KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: e712c8e276321dbddc96b7c13bab5e1acdfdea88
Local-runs: none
Scope: packages/app-shell/src/console/marketplace/InstalledListWidget.tsx, packages/app-shell/src/console/marketplace/MarketplaceInstalledPage.tsx, packages/app-shell/src/console/marketplace/MarketplaceRowActions.tsx, packages/app-shell/src/console/marketplace/tests/InstalledListWidget.kernelNoteTooltip-12610.test.tsx, packages/app-shell/src/console/marketplace/tests/InstalledListWidget.notLoaded-11645.test.tsx, packages/app-shell/src/console/marketplace/tests/MarketplaceRowActions.installedAppsPins.test.tsx, packages/app-shell/src/console/marketplace/tests/marketplaceDates.displayLocale-10331.test.tsx, packages/app-shell/src/console/marketplace/tests/walledCatalogPackageRefusal-7611.test.tsx, packages/app-shell/src/console/marketplace/marketplaceApi.ts, packages/app-shell/src/views/metadata-admin/PackagesPage.confirmFlows-11784.test.tsx, packages/app-shell/src/views/metadata-admin/PackagesPage.source-12675.test.tsx, packages/app-shell/src/views/metadata-admin/PackagesPage.tsx, packages/app-shell/src/views/metadata-admin/PackagesPage.walledCatalogRefusal-7611.test.tsx, packages/app-shell/src/views/metadata-admin/i18n.ts, packages/app-shell/src/views/metadata-admin/packageSource.ts, packages/i18n/src/locales/ar.ts, packages/i18n/src/locales/de.ts, packages/i18n/src/locales/en.ts, packages/i18n/src/locales/es.ts, packages/i18n/src/locales/fr.ts, packages/i18n/src/locales/ja.ts, packages/i18n/src/locales/ko.ts, packages/i18n/src/locales/pt.ts, packages/i18n/src/locales/ru.ts, packages/i18n/src/locales/zh.ts + .changeset/12675-installed-apps-keys.md, .changeset/12675-packages-source.md, packages/app-shell/src/index.ts, packages/app-shell/src/console/AppContent.tsx, packages/app-shell/src/urlParams.ts, the contract review 6219326691 on this PR, objectstack scripts/pm/clause2-line.mjs, objectstack scripts/pm/record-recognisers.mjs, objectstack scripts/check-governed-merges.mjs

Face: narrowing — the PR widens (Source column, marketplace row actions, the ?source= filter spelling objectstack-ai/objectstack#23933 binds to) and narrows (seven published marketplace.* keys leave all ten @object-ui/i18n packs; the published marketplace:installed-list widget and the exported MarketplaceInstalledPage redirect instead of drawing a list). Re-render on the rework head after the FAIL record 6219326691 at 681c066, which failed on the declaration alone.

Inputs: card #12675 — body, claim 6217043127, dev report 6218334568 with the seat's answers, rework delta 6219557358; PR #12722 — body (line 2 reads Clause-②: yes (narrowing)), file list (27 paths, 1233 added, 872 deleted), every comment including 6219326691 and the REWORK record 6219343416; the net diff of the head against its merge-base with origin/main (f8267df93a); the check-runs on e712c8e2. Check-runs on the head: every run completed with conclusion success — Lint, Type Check, Build and E2E, Build Docs, Bundle Analysis, Repo Gates, Line Citation Gate, Governed Surface Queue Guard, Changeset Declaration, Changeset Claim Re-read, Changeset Bump Policy, Changeset Fixed Group Check, Changeset Overwrite Report, Test, Test (dist pins), Test shards 1 to 16 of 16, Live E2E (informational), label — and Test (coverage), the coverage shard matrix and dependabot read skipped by their own conditions. None failed. Those conclusions are the gate verdicts; nothing was built, run or re-run here.

Head delta, proven by diff. e712c8e2 has one parent, 681c066b; git diff 681c066b..e712c8e2 touches exactly two paths, .changeset/12675-installed-apps-keys.md (4 added) and .changeset/12675-packages-source.md (4 added, 1 deleted — one bullet re-wrapped with a sentence appended), 7 insertions and 1 deletion in all, both frontmatters byte-identical. No code, test, locale or config path moved. The rework delta's claim of one prose-only commit with no merge, rebase, amend or force-push holds. The code half is therefore the tree 6219326691 judged, and its ① judgments are adopted below by citation.

① Derived judgments

Adopted by citation from 6219326691, whose code half the earlier record judged RIGHT on every item and which this head carries unchanged: the seven-key removal across all ten packs (readers at the merge-base were exactly the retired list body, the retired page header and the two deleted widget tests; no reader remains in objectui or objectstack; the marketplace namespace only shrinks under ADR-0060 rule 3); the marketplace:installed-list widget rendering a replacing Navigate to the filtered Packages URL with its registration unchanged, so objectstack's served marketplace_installed page still resolves; the MarketplaceInstalledPage export and both system/marketplace/installed routes kept; the two deleted InstalledListWidget.* test files replaced at a layer at least as close in MarketplaceRowActions.installedAppsPins.test.tsx; the closed Source derivation in packageSource.ts with PACKAGE_SOURCE_UNKNOWN and PACKAGE_SOURCE_CONFLICT refusals; the strict marketplace list read joined by Promise.all; the two row-action gates (features.installLocal and useWorkspaceAdminStatus().isAdmin); no second copy of Update or Re-seed / Purge; ?source= refusing unknown, empty and repeated values with source outside RESERVED_URL_PARAMS; the pending .changeset/12288-marketplace-install-mode.md still true; the carried installedAdditiveNote sentence owned by objectui#12684.

Spot-checked on this head's tree, read-only, each consistent with the citation: no code, test or doc under packages/, apps/ or examples/ outside the ten packs reads any of the seven keys; each of the ten packs holds zero of the seven; ComponentRegistry.register('marketplace:installed-list', …) is still the one registration; src/index.ts still exports MarketplaceInstalledPage; both routes stand in AppContent.tsx; source is not in RESERVED_URL_PARAMS.

Landing note, not a judgment on this head: origin/main has moved past the merge-base and touches PackagesPage.tsx and i18n.ts (the #12662 header rewrite the claim anticipated) and the ten locale packs (no marketplace.* line in main's side); the lander's merge of main moves the head, and this record binds to e712c8e2.

② Semver level

  • The Clause-②: line — RIGHT on every carrier. Read with the fleet's one reader, readClause2Line (objectstack scripts/pm/clause2-line.mjs), over the three texts the face is read from: the PR body line 2 reads declared / yes / narrowing; .changeset/12675-installed-apps-keys.md reads declared / yes / narrowing; .changeset/12675-packages-source.md reads declared / yes / narrowing. Each line sits at the start of a line, once per text, with no describing or inline near miss and no second declaration. reviewFace (objectstack scripts/pm/record-recognisers.mjs) over the PR's 27 paths under the objectui register with those three texts handed as declaredOn answers face: narrowing, tierName: CONTRACT_REVIEW_TIER, with empty schema and rules hits — no published schema and no governed path in the diff — so CONTRACT_REVIEW_TIER is the exact tier of this record and the declaration face a TIER_DEFAULT record would stand on is not the face this tree reads. The claim comment's own Clause-②: yes (no arm) is the dispatch's statement, not a committed carrier, and decides nothing. Finding of 6219326691 closed.
  • @object-ui/i18n: minor — RIGHT. objectui's fixed group carries a breaking change as minor with the break spelled out in the body (check-changeset-no-major.mjs, the Changeset Bump Policy run on this head, green). The body names the seven keys, the one reader that left, the host consequence (the key comes back instead of a sentence) and now the one-line fix the earlier record asked for: "carry the sentence in the host's own bundle, or drop the read". Wording addition one of two — present, verbatim.
  • @object-ui/app-shell: minor — RIGHT. A new column, a new filter spelling and a changed render of a published widget and export, each in the body, and the body states the widget registration, the route and the export are kept until objectstack#23933. The sentence the earlier record asked for is now in the row-actions bullet: with features.installLocal off no row reads Marketplace, so in such an environment control-plane installs read Code, and the declared key objectstack#23972 adds removes that case. Wording addition two of two — present.
  • Coverage of what the diff publishes: 25 source paths of two released packages, two changesets, one per package (Changeset Declaration, the presence gate, green on this head; Changeset Fixed Group Check green). No major, no skip-changeset. objectui's register carries no ADR-0087 disposition gate (that marker is an objectstack changeset rule), so none is owed here.

③ Boundary flags

Five open_questions in the dev report 6218334568, the seat's answers A, A, A, declared, A; the rework delta 6219557358 carries none.

  1. Source signal contract → A. Answered. packages API: the served installed-package row declares no origin. Declare a closed source (code / marketplace / authored); objectui's Packages Source column joins the undeclared writable with a second read today objectstack#23972 is open (domain:spec, area:api, pm:queue); the interim strict join stands per ①.
  2. Update and Re-seed / Purge as row controls → A. Answered; one owner per action, reached through Details; B is a follow-up card only if the maintainer asks.
  3. Retirement follow-up → A. Answered and now filed: objectui#12733 is open, first body line Blocked-by: objectstack-ai/objectstack#23933, labelled pm:blocked, and names the registration, the widget file, both routes, the export and the Installed (N) button. The earlier record's "pending seat act" is discharged.
  4. Narrowing → declared. Answered in committed form on this head (② above).
  5. The installLocal-off edge → A. Answered, and the behaviour is now explicit in the app-shell changeset.

Dev flags: the class-a Scope badge finding is objectui#12723 (open, finding); the tolerant listLocalInstalls on the marketplace pages is in the PR's acceptance notes; the two fixtures that gained writable: true match every served row carrying the verdict. The rework delta's gate claims (check:changeset-claims, changeset:check, check-changeset-presence at exit 0) agree with the head's Changeset Claim Re-read, Changeset Fixed Group Check and Changeset Declaration conclusions. Nothing escalated.

Implemented-by: claude/issue-12675-packages-source
Reviewed-by: session_011K9g23W67dy2zwnyzaoB6o

VERDICT: PASS

Rendered read-only on the rework head; the code half stands by citation of 6219326691, the declaration and both changesets re-judged in full.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · domain:ui seat 1 · session_011K9g23W67dy2zwnyzaoB6o · 2026-10-16T16:24Z

What was reviewed:

  1. Shape.
    • Fixes #12675 is the first line and the only closing keyword. Clause-②: yes (narrowing) starts line 2 of the body and a line in both committed changesets. The assignee is os-tesla.
    • 27 files, NOT governed.
    • The head delta from 681c066 is the two changesets' prose only (proven by diff in the record).
    • Surface on record: metadata-admin/i18n.ts (new Packages copy, en and zh) and the new packageSource.ts sibling, in the claim's list-body region.
  2. The widening.
  3. The narrowing.
    • Seven marketplace.* keys leave all ten @object-ui/i18n packs. No reader is left in objectui or objectstack, and the changeset gives hosts the one-line fix.
    • marketplace:installed-list and MarketplaceInstalledPage now redirect to the filtered Packages URL, and the registration, routes and export are kept. objectstack's served marketplace_installed page therefore still resolves until #23933 retargets it.
  4. Gates (check-runs pinned to this head).
    • Every run is success, including Lint, Type Check, Test with all 16 shards, Test (dist pins), Build & E2E, Bundle Analysis, Live E2E (informational) and every changeset check.
    • The eight ablations each go red, and the restored blobs equal HEAD.
    • The pending .changeset/12288-marketplace-install-mode.md, which names marketplaceApi.ts, is still true at this head.
  5. Carried, each with its carrier:
  6. Landing.

Generated by Claude Code

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

Projects

None yet

2 participants