Skip to content

fix(console,i18n): install answers say what the runtime served (objectui#12098) - #12129

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-12098-install-served-truth
Oct 11, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-12098-install-served-truth

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #12098
Clause-②: yes

What changes

Two readers of an install answer now say what the runtime served.

One new locale key, marketplace.install.localLoadsAtRestart, is in all ten packs with a real translation. No spec type is imported.

Premises, measured on objectui main 29b99490 and objectstack main e84aeb36 (read through gh api contents)

  • H1 holds. doInstallLocal showed localSuccess on any 200, then ran refreshMetadata('app') and emitMetadataRefresh(). It never read hotLoaded. LocalInstallResult already types hotLoaded: boolean, so marketplaceApi.ts is unchanged.
  • H2 holds. isAppOf matched _packageId alone. _packageVersion is declared beside _packageId in packages/spec/src/kernel/metadata-protection.zod.ts ("Owning package version."). objectstack PR #22724 (b62260cb) stamps it on every app the registry path registers, at the top level of each item that GET /meta/app serves. That is the list the wait already polls.
  • H3: the page holds three versions at that moment. They are installResp.installation.version (the answer), data.package.latest_version.version (the catalog), and data.versions[0].version. The wait uses the answer's version only. A guessed catalog version that was not the one installed would turn a good install into a five-minute timeout. With no version, the worst case is today's early refresh.
  • H4 holds. install-local has no rebuild window (the report on objectui#12087), and on false nothing of the package is served before the restart. So no wait runs: the page sets the message and returns.
  • H5 holds. The ten packs are packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts.
  • H6 holds. marketplace-install-local-plugin.ts answers hotLoaded: hotLoadError === undefined and adds hotLoadError only beside false. The field and its type are unchanged.

Where it lands, and one addition beyond the claim's wording

  • waitForServedApp.ts: the predicate and its docblock.
  • MarketplacePackagePage.tsx: the hotLoaded reader, and the version carried into the wait and "Check again".
  • MarketplacePage.tsx: the catalog's waitForServedApp call passes the answer's version. The claim names this call.
  • Beyond the claim's wording: the catalog's install-local branch now reads hotLoaded too.
    • git grep "installLocal(" outside tests finds two readers of the install-local answer: the package page and this branch.
    • This branch installs an org package by id with versionId: 'latest'. That is a cloud-fetched manifest, the lenient path's own case.
    • It said "Installed NAME", and its comment claimed "the live registry already holds it", before it sent the refresh pulse.
    • It now shows the same restart key and sends no pulse on false. The file is on the claim's surface. The fix is the same defect, the same key and the same shape, and adds no new gate family.
  • The census pin de-quote-pairing-3876.test.ts moves from 76 to 77: the new de value quotes the name („NAME“), one matched pair.
  • No docs page describes these messages. content/docs and packages/app-shell/README.md were searched for the install wording, install-local, hotLoaded and _packageId, and the only hits were unrelated. No doc edit.

Tests

  • waitForServedApp-12098.test.ts (unit, virtual clock):
    • an upgrade from 1.0.0 to 1.1.0 keeps reading while 1.0.0 is served and settles on the 1.1.0 app: 4 reads, 3 sleeps;
    • 1.0.0 served for the whole bound gives served: false;
    • CONTROL: an app with no _packageVersion is accepted on the id at the first read.
  • MarketplacePackagePage.servedTruth-12098.test.tsx (the real MetadataProvider, the real bus, and the real waitForServedApp on a virtual clock):
    • Acceptance 1: a 200 with hotLoaded: false shows localLoadsAtRestart, not localSuccess. After the install there are 0 GET /meta/app reads, 0 pulses, 0 app seed writes and no wait. CONTROL: hotLoaded: true keeps localSuccess, reads the list and sends one pulse.
    • Acceptance 2: an update from 1.0.0 to 1.1.0 waits with version: '1.1.0'. While 1.0.0 is served there is no pulse, no seed write and the status stays "Deploying". At the landing interval there is one pulse, and every seed write after the install carries the 1.1.0 app. CONTROL: an app with no _packageVersion is accepted on the first read with no sleep.
  • MarketplacePage.orgInstallWaitServed-12097.test.tsx:
    • its waits now record the version ('1.0.0');
    • its install-local fixture gains the real wire's hotLoaded: true. It lacked the field, which the declared type requires;
    • a new case pins the catalog's hotLoaded: false branch: the restart wording, no pulse, no seed write and no wait.
  • waitForServedApp-12087.test.ts: its six calls pass version: undefined, the id-only reading those cases pin.

Runs, all from the repo root under the shared verify lock:

  • vitest run packages/app-shell/src/console/marketplace/: 29 files and 183 tests passed, at b1db713. The only later commit, 35e1bb0, touches only packages/i18n/src/__tests__/de-quote-pairing-3876.test.ts.
  • vitest run packages/i18n/: 82 files passed, 1316 tests passed and 13 skipped, at 35e1bb0.
  • pnpm --filter @object-ui/app-shell type-check (it echoes tsc --noEmit && tsc -p tsconfig.test.json): exit 0 at b1db713, after the dependency closure was built.
  • pnpm --filter @object-ui/i18n type-check: exit 0 at 35e1bb0.

Reverse verification

Run at e69d49b. Each leg went through scripts/ablation-replace.mjs: the anchor must hit, the mutation is proven on disk by count and blob, and the restore is proven as blob equals HEAD with git diff HEAD empty. The tests resolve the sources by relative import, so no dist/ sits in the path.

  • A: the version clause in isAppOf set to return true;. Predicted 3 red, observed 3 red: the two unit upgrade cases and the page's upgrade case. Both CONTROLs stayed green.
  • B: the package page's if (!result.hotLoaded) set to if (false). 1 red: the hotLoaded: false case.
  • C: the catalog's pulse guard set to if (true). 1 red: the catalog hotLoaded: false case.
    • The first attempt was refused by the tool, because its replacement was a substring of the anchor. It was re-run with a distinct replacement.
  • D: the catalog's restart wording replaced by marketplace.org.installed. 1 red: the same case.

Gates

Gates run at 35e1bb0, the final head, each exit 0 unless stated:

  • pnpm check:i18n-keys, check:i18n-drift (1 key added, 0 en values changed), check:i18n-dead-keys, check:i18n-designer-parity.
  • node scripts/check-changeset-presence.mjs, check:changeset-claims, check:pending-changeset-literals.
  • check:new-line-citations (0 new), check:control-bytes, check:test-path-roots, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:phantom-deps.
  • check:self-import, check:esm-specifiers, check:unreferenced-sources, check:spec-symbols, check:side-effects-array, check:unused-deps, check:doc-example-readers.
  • Ratchets: column-identity.ratchet.test.ts and one-authority-per-exported-name-6273.test.ts (2 files, 18 tests); the root suite vitest run scripts/__tests__/ (179 files passed, 2 skipped; 5452 tests passed).
  • Eager closure, after a head apps/console build at 35e1bb0:
    • check:eager-closure passed at 3171.7 KB gzipped against a 3204.6 KB budget;
    • check:eager-locale-catalogues passed: en is the only resident catalogue;
    • the new and changed code (waitForServedApp, MarketplacePackagePage, MarketplacePage) sits in lazy chunks, none of them among the 290 eager files;
    • the eager delta is the en entry alone: 162 raw bytes, 37 gzip bytes. This was measured on the head chunk with and without the entry. No base build was made, so it is not a base-to-head bundle diff.
  • eslint, narrowed: eslint --no-inline-config --format json over the branch's 18 changed .ts/.tsx files gives 0 errors. The 13 warnings are the base counts unchanged: 11 in MarketplacePackagePage.tsx and 2 in MarketplacePage.tsx, measured on the base blobs. eslint.config.js sets no parserOptions.project or projectService, so this diff cannot move a verdict on an untouched file. Repo-wide pnpm lint is left to CI.

Acceptance notes

  • hotLoadError, which is served beside false, is not shown. The card asks for the restart wording only. No carrier.
  • The wait assumes that the control plane's installation.version is the manifest version the runtime stamps as _packageVersion. The cloud repo is not readable from this seat. If the two ever differed, the wait would end in the timeout state with "Check again", not in a refresh of a wrong list.
  • On a hotLoaded: false local result, the suggested-bindings panel still mounts, as before. Whether the runtime records suggestions for a package its kernel did not register was not measured.

Session: https://claude.ai/code/session_01TYgwmFK1q4KJ6Qq2WRLzsD


Generated by Claude Code

…2098)

An install-local answered `hotLoaded: false` (objectstack#22695) now reads
"installed, loads when the runtime next restarts" on the package page and
the catalog strip, and refreshes no app list. The served-app wait now also
matches the version the install answer names against `_packageVersion`
(objectstack#22689), so an upgrade keeps waiting while the stale kernel
serves the old version; an app with no `_packageVersion` counts on its id.

New locale key `marketplace.install.localLoadsAtRestart` in all ten packs.

Claude-Session: https://claude.ai/code/session_01TYgwmFK1q4KJ6Qq2WRLzsD
Co-authored-by: Claude <noreply@anthropic.com>
… case asserts the waiting state (objectui#12098)

Claude-Session: https://claude.ai/code/session_01TYgwmFK1q4KJ6Qq2WRLzsD
Co-authored-by: Claude <noreply@anthropic.com>
…ame (objectui#12098)

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 290 chunks) 3171.9 KB 3204.6 KB
Main entry chunk (gzip) 74.1 KB 350 KB
Entry file index-B9KHlMH_.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) 19.75KB 7.29KB
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) 18.15KB 5.40KB
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.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
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) 586.97KB 141.32KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 240.39KB 67.09KB
fields (index.js) 274.56KB 69.81KB
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.26KB 11.71KB
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.31KB 15.86KB
plugin-charts (index.js) 84.72KB 23.27KB
plugin-chatbot (index.js) 201.52KB 47.99KB
plugin-dashboard (index.js) 144.20KB 38.95KB
plugin-designer (index.js) 233.53KB 49.80KB
plugin-detail (index.js) 249.33KB 65.74KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 177.59KB 46.00KB
plugin-gantt (index.js) 179.17KB 45.07KB
plugin-grid (index.js) 251.36KB 69.68KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 122.77KB 31.19KB
plugin-map (index.js) 27.24KB 9.03KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 92.11KB 23.27KB
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.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
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-components.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: 35e1bb0558c61cd96d26d9e50f8c1dc4d1ce73d8
Local-runs: none

Inputs: card objectui#12098 (its body and its three comments: the unlock scan 6102113934, the claim 6106224958, the os-dev-report 6106762868); PR objectui#12129 (its body, its 19-file list, the net diff against main); the head's check-runs; and, where the diff's context needed it, file contents at the head (@object-ui/app-shell's src/index.ts and package.json, the two marketplace pages, marketplaceApi.ts). Nothing built, run or re-run. This record was written at 2026-10-11T07:51Z.

① Derived judgments

  1. @object-ui/i18n published surface WIDENS by one key: marketplace.install.localLoadsAtRestart in all ten packs (ar de en es fr ja ko pt ru zh), so TranslationKeys gains it. Right, and it is the only published-surface change in the diff. Each value follows its pack's quote convention beside localSuccess (de with low-high German quotes, ja with corner brackets, the rest straight quotes); the en value carries no tracker number (the tracker refs sit in a source comment, which is allowed).
  2. waitForServedApp.ts: ServedAppWaitOptions gains a REQUIRED version: string | undefined; ServedApp gains an optional _packageVersion; isAppOf now also matches _packageVersion when both the caller and the served app name one. NOT a public surface: @object-ui/app-shell's entry (src/index.ts; exports maps . and ./styles.css only) re-exports MarketplacePage, MarketplacePackagePage and MarketplaceInstalledPage, none of which takes props, and waitForServedApp is not re-exported, so nothing reaches these types from the entry. Internal; the required option is a deliberate compile-time forcing of the two callers (the package page and the catalog page; MarketplaceInstalledPage and InstalledListWidget do not call it). Right.
  3. The predicate's fallback matches the card: an answer that names no version, or a served app that wears no _packageVersion (a runtime before the stamp), is accepted on _packageId alone; otherwise the version must equal. Right. Pinned by waitForServedApp-12098.test.ts on a virtual clock (1.0.0 to 1.1.0: 4 reads, 3 sleeps, settles on the 1.1.0 app; 1.0.0 for the whole bound gives served: false; CONTROL: an unstamped app is accepted on the first read with no sleep).
  4. MarketplacePackagePage, doInstallLocal: on hotLoaded: false it sets localLoadsAtRestart and returns before refreshMetadata('app') and emitMetadataRefresh(); on true the path is today's. The early return does NOT skip the local-install ledger: the listLocalInstalls effect keys on localResult, which is set before the return, so the installed badge, the notLoaded badge and the local menu still refresh. Right. Acceptance (1) is pinned in MarketplacePackagePage.servedTruth-12098.test.tsx with the real MetadataProvider, the real bus and the real wait: 0 app reads, 0 pulses, 0 seed writes, no wait; CONTROL hotLoaded: true keeps localSuccess, reads the list and sends one pulse.
  5. MarketplacePackagePage upgrade wait: awaitServedInstall(manifestId, installResp?.installation?.version) carries the answer's own version (InstallResponse.installation is optional, so the type is exactly string | undefined), never the catalog's latest; DeployState carries version, so "Check again" re-waits for the same one. Right. Acceptance (2) is pinned at page level too: no pulse or seed write while 1.0.0 is served, one pulse at the landing interval, every seed write after the install carries 1.1.0; CONTROL: an unstamped app settles with no sleep.
  6. MarketplacePage, awaitServedOrgInstall: the cloud-install answer is now captured and its version passed the same way; OrgDeployState carries it, so the catalog strip inherits the predicate as the unlock scan asked. Right; the 12097 pins now record version: '1.0.0'.
  7. MarketplacePage, doOrgInstall install-local branch (beyond the claim's wording): installLocal's hotLoaded is read; false shows localLoadsAtRestart and skips emitMetadataRefresh(); await load() still runs on both branches, so installedIds refresh from the ledger. Right as code; its scope standing is judged under ③ item 1.
  8. Test consequences: the six waitForServedApp-12087 calls add version: undefined and keep their id-only meaning; the 12097 fixture gains the wire's hotLoaded: true (the declared LocalInstallResult requires it) and lists a local install whether or not hot-registered, which is the runtime's real ledger behaviour; de-quote-pairing-3876 moves 76 to 77 and 77/77/0 for the one new matched pair around the name placeholder. All mechanical and right.
  9. The card's remaining criteria: no new spec type imported (the diff adds no @objectstack/spec import); marketplaceApi.ts unchanged (hotLoaded: boolean was already typed); no governed surface and no packages/spec/src/** in the file list; head repo is the base repo; 618 changed lines.
  10. Nothing in the diff narrows a published accept-set. The Clause-② direction is ruled WIDENING.

② Semver level

Changeset .changeset/12098-install-served-truth.md: @object-ui/app-shell: patch, @object-ui/i18n: minor. Matches what the diff publishes: app-shell ships a behaviour fix with no public-surface change (patch); i18n publishes one new key, a widening of TranslationKeys (minor, which meets the "yes takes at least minor" floor on the package whose surface widens). No major (objectui's fixed-group rule); no skip-changeset. The body's prose was read against the diff sentence by sentence and holds: both readers, both wordings, the no-refresh on false, true unchanged, the version match and its two fallbacks.

Clause-②: yes on the claim and at the head of the PR body; yes (widening) in the changeset body. Consistent, and the direction is confirmed in ① item 10.

③ Boundary flags

Dev deviations (os-dev-report 6106762868), each answered:

  1. Surface addition: MarketplacePage's doOrgInstall reads hotLoaded. ACCEPTED under the bounded in-place-fix exemption; the four conditions read as holding from the diff and the card thread: same defect class (the same install-local answer, unread); mechanical and pinned (the new case in the 12097 file plus ablations C and D); the file is on the claim's surface and, per the claim's and the dev's readings (not re-measured here), no other claim holds it; same gate family, no new verification surface. The exemption owes two things: the PR body names the fix with evidence (done), and the claim's File surface: line is amended in the same round. ESCALATED to the seat as an action: amend the claim to name the catalog's install-local branch.
  2. Tests outside the named pins: mechanical consequences of a required option, a required field and one matched quote pair. Right (① item 8).
  3. No docs page edit: accepted; the diff adds no authorable key and no documented surface, and the search is stated.
  4. The marketplace vitest folder and the app-shell type-check ran at b1db713, not at the head; the final commit touches only the i18n census test: accepted. The head's Type Check and Test (shard n/8) check-runs are the verdicts for that gap and were still in progress at the read below.
  5. Eager delta measured head-with versus head-without the en entry, no base build: accepted as a declared narrowing; Bundle Analysis on the head is the base-to-head reading and concluded success.
  6. Lock-wait timeout, re-run with the kept slot: not a measurement; noted.
  7. Footer: the stored PR body ends with exactly one session-URL footer, the form objectui's rules keep for a PR body. Right.
  8. Worktree removed after the PR opened: housekeeping; noted.

Out-of-scope findings (carrier none; noted in the PR's Acceptance notes), each answered:

  • hotLoadError not shown: zero pull, the card asks for the restart wording only. Acceptance notes is the right carrier; no card.
  • SuggestedBindingsPanel still mounts on a hotLoaded: false local result: it mounted on every 200 before this diff too (localResult.ok gates it), so not a regression; unmeasured, so an observation and not a class (a) defect. Acceptance notes; the seat may card it only with a measured reach.
  • The wait assumes installation.version equals the manifest version the runtime stamps as _packageVersion: this is the card's own design (the wait's predicate "also names the installed version"), and a mismatch ends in the honest timeout with "Check again", never a wrong-list refresh. Acceptance notes is right. ESCALATED as a note, not a blocker: on a stamping runtime, a control-plane version spelled differently would time out every in-environment cloud install, so one reading against cloud is worth taking by a seat that can read it.

open_questions: none filed; none owed.

Check-runs on the head, read at 2026-10-11T07:48:47Z: 31 completed with conclusion success (among them Lint, Build and E2E, Bundle Analysis, Changeset Declaration, Changeset Bump Policy, Changeset Claim Re-read, Changeset Fixed Group Check, Changeset Overwrite Report, Governed Surface Queue Guard, Line Citation Gate, Inert vi.mock Specifier Check, Control Byte Scan, Test (dist pins), Test (shard 4/8), Test (shard 8/8)); 3 completed with conclusion skipped (the coverage matrix placeholder, Test (coverage), dependabot); 8 still in progress with no conclusion yet (Type Check, Test shards 1, 2, 3, 5, 6 and 7 of 8, Spec Main Shape Gate). No failure at that read. The seat's landing check ② (every check green) was therefore not yet met at that read; this record is the landing check ① record and does not stand in for ②.

Implemented-by: claude/issue-12098-install-served-truth
Reviewed-by: session_01TYgwmFK1q4KJ6Qq2WRLzsD

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 11, 2026 07:57
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 11, 2026 07:57
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 11, 2026
Merged via the queue into main with commit 1071393 Oct 11, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-12098-install-served-truth branch October 11, 2026 08:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants