This repository was archived by the owner on Oct 26, 2026. It is now read-only.
Repository navigation
Commit 1071393
fix(console,i18n): install answers say what the runtime served (objectui#12098) (#12129)
Fixes #12098
Clause-②: yes
## What changes
Two readers of an install answer now say what the runtime served.
- **An install-local answered `hotLoaded: false`.** The runtime
installed the package, but its running kernel could not register it.
This is the lenient path for a cloud-fetched manifest
(objectstack-ai/objectstack#22695). The package loads at the runtime's
next restart.
- The package page (`doInstallLocal`) used to show
`marketplace.install.localSuccess` ("should now appear in the app
switcher") and refresh the app list. It now shows the new
`marketplace.install.localLoadsAtRestart`: installed, loads when the
runtime next restarts, not in the app switcher until then. It does not
run `refreshMetadata('app')` or `emitMetadataRefresh()`.
- `hotLoaded: true` keeps today's wording and refresh.
- **An upgrade waits for the new version's app.** `waitForServedApp`
takes a `version` option. Its type is `string | undefined` and it is
required, so every caller has to decide what to pass. An app that wears
`_packageVersion` counts only at that version. An app that wears none
comes from a runtime that predates objectstack-ai/objectstack#22689, and
it counts on its `_packageId` alone, as today.
- The package page passes the version the install answer names
(`installation.version`). An answer that names none waits on the id
alone. "Check again" waits for the same version.
- The catalog's org strip passes its answer's version the same way, so
it inherits the predicate as triage asked (`6102113934`).
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](https://claude.ai/code/session_01TYgwmFK1q4KJ6Qq2WRLzsD)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 802f0bc commit 1071393
19 files changed
Lines changed: 565 additions & 53 deletions
File tree
- .changeset
- packages
- app-shell/src/console/marketplace
- __tests__
- i18n/src
- __tests__
- locales
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
96 | | - | |
| 96 | + | |
| 97 | + | |
97 | 98 | | |
98 | 99 | | |
99 | | - | |
100 | | - | |
101 | | - | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
102 | 103 | | |
103 | 104 | | |
104 | 105 | | |
| |||
352 | 353 | | |
353 | 354 | | |
354 | 355 | | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
355 | 360 | | |
356 | | - | |
357 | | - | |
| 361 | + | |
| 362 | + | |
358 | 363 | | |
359 | 364 | | |
| 365 | + | |
360 | 366 | | |
361 | 367 | | |
362 | 368 | | |
| |||
367 | 373 | | |
368 | 374 | | |
369 | 375 | | |
370 | | - | |
| 376 | + | |
371 | 377 | | |
372 | 378 | | |
373 | 379 | | |
| |||
391 | 397 | | |
392 | 398 | | |
393 | 399 | | |
394 | | - | |
| 400 | + | |
395 | 401 | | |
396 | 402 | | |
397 | 403 | | |
| |||
424 | 430 | | |
425 | 431 | | |
426 | 432 | | |
427 | | - | |
428 | | - | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
429 | 437 | | |
430 | 438 | | |
431 | 439 | | |
| |||
450 | 458 | | |
451 | 459 | | |
452 | 460 | | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
453 | 471 | | |
454 | 472 | | |
455 | 473 | | |
456 | 474 | | |
457 | 475 | | |
458 | 476 | | |
459 | 477 | | |
460 | | - | |
461 | | - | |
462 | | - | |
463 | | - | |
| 478 | + | |
464 | 479 | | |
465 | 480 | | |
466 | 481 | | |
| |||
780 | 795 | | |
781 | 796 | | |
782 | 797 | | |
783 | | - | |
| 798 | + | |
784 | 799 | | |
785 | 800 | | |
786 | 801 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
117 | 117 | | |
118 | 118 | | |
119 | 119 | | |
120 | | - | |
| 120 | + | |
| 121 | + | |
121 | 122 | | |
122 | 123 | | |
123 | | - | |
124 | | - | |
125 | | - | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
126 | 127 | | |
127 | 128 | | |
128 | 129 | | |
| |||
229 | 230 | | |
230 | 231 | | |
231 | 232 | | |
232 | | - | |
| 233 | + | |
233 | 234 | | |
234 | 235 | | |
235 | | - | |
| 236 | + | |
236 | 237 | | |
237 | 238 | | |
| 239 | + | |
238 | 240 | | |
239 | 241 | | |
240 | 242 | | |
| |||
243 | 245 | | |
244 | 246 | | |
245 | 247 | | |
246 | | - | |
| 248 | + | |
247 | 249 | | |
248 | 250 | | |
249 | 251 | | |
250 | | - | |
| 252 | + | |
251 | 253 | | |
252 | 254 | | |
253 | 255 | | |
| |||
266 | 268 | | |
267 | 269 | | |
268 | 270 | | |
269 | | - | |
270 | | - | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
271 | 282 | | |
272 | | - | |
273 | | - | |
| 283 | + | |
| 284 | + | |
274 | 285 | | |
275 | 286 | | |
276 | | - | |
| 287 | + | |
277 | 288 | | |
278 | | - | |
| 289 | + | |
279 | 290 | | |
280 | 291 | | |
281 | 292 | | |
282 | 293 | | |
283 | 294 | | |
284 | | - | |
| 295 | + | |
| 296 | + | |
285 | 297 | | |
286 | 298 | | |
287 | 299 | | |
| |||
393 | 405 | | |
394 | 406 | | |
395 | 407 | | |
396 | | - | |
| 408 | + | |
397 | 409 | | |
398 | 410 | | |
399 | 411 | | |
| |||
0 commit comments